- •Часть 2 (продолжение): Прикладное программирование в Windows
- •Глава 8. Виртуальное окно: работа с текстом
- •8.1. Оконные координаты, цвета, отображение строк
- •Кодировка rgb-значений
- •Размеры системных метрик
- •8.2. Виртуальное окно
- •Способы заполнения прямоугольной области
- •8.3. Изменение шрифтов
- •Макроимена распространенных шрифтов
- •8.4. Создание собственных шрифтов
- •Глава 9. Программирование графики
- •9.1. Логическая система координат
- •Рекомендуемый самый яркий состав цветов
- •9.2. Пиксели, линии, дуги, прямоугольники, эллипсы и секторы
- •9.3. Работа с перьями и кистями
- •Типы линий, создаваемых пером
- •9.4. Технология виртуального окна
- •9.5. Режимы отображения и области вывода
- •Текущий режим отображения (mappind mode)
- •Глава 10. Работа с панелями инструментов
- •10.1. Общие элементы управления
- •Общие элементы управления
- •10.2. Подключение и инициализация общих элементов управления
- •10.3. Работа с панелью инструментов
- •Начальные состояния кнопок панели инструментов
- •Стиль кнопки определяется (значения поля fsStyle)
- •Сообщения к панели инструментов
- •10.4. Создание растрового изображения для панели инструментов
- •10.5. Включение подсказок
- •Глава 11. Спины, ползунки и индикаторы процессов
- •11.1. Работа со спином
- •Стили «up-down control»
- •Сообщения, которые можно посылать спину
- •11.2. Создание спина с «приятельским» окном
- •11.3. Работа с ползунком
- •Значения стилей для ползунка
- •Перечень сообщений, которые можно посылать ползунку
- •Перечень нотификационных сообщения ползунка
- •11.4. Индикатор процесса
- •Управляющие сообщения индикатору
- •Глава 12. Многозадачность: процессы и потоки
- •12.1. Создание нового процесса (отдельной задачи)
- •Разрешенные значения поля dwFlags
- •12.2. Многопотоковые программы
- •12.3. Работа с несколькими потоками
- •12.4. Синхронизация процессов и потоков: семафоры
- •12.5. Обработка событий
- •Глава 13. Приемы программного управления вычислительным процессом
- •13.1. Использование функций Проводника Explorer для работы в файловой системе
- •Управляющая информация Проводника
- •Режимы обработки файлов
- •13.2. Создание собственных динамических библиотек (dll-файлов)
- •13.3. Работа с буфером обмена Clipboard
- •Функции подсистемы Clipboard
- •Свойства выделяемого блока памяти
- •Форматы и типы данных
- •Литература
12.3. Работа с несколькими потоками
В принципе, программа может иметь столько потоков, сколько их может поддерживать текущая конфигурация операционной системы. Например, новая версия предыдущего примера, которая приводится ниже, создает по команде Новый поток сразу два потока. Для того чтобы убедиться, что параллельно выполняются два потока, они генерирует звуки разной тональности с различными паузами:
более высокий звук 600 Гц с задержкой между звуками 0,5 сек;
звук низкой тональности 300 Гц с задержкой между звуками 0,2 сек.
Продолжительность обоих звуков 0,25 сек.
Пример 12-3. Программа с двумя порожденными потоками
// Многопотоковая программа с двумя потоками,
// с использованием виртуального окна
#include <Windows.h>
#include <String.h>
#include <Stdio.h>
#include "Proc.h"
#define Procmax 5
LRESULT CALLBACK WindowFunc(HWND,UINT,WPARAM,LPARAM);
DWORD MyThread1(LPVOID); // Функция 1-го потока
DWORD MyThread2(LPVOID); // Функция 2-го потока
char szWinName[] = "МоеОкно"; // Имя класса окна
char str[255]; // Буфер строки вывода
int X=0, Y=0; // Текущие координаты строки
int procnum=0; // Количество активных процессов
DWORD Tid1; // Идентификатор 1-го потока
DWORD Tid2; // Идентификатор 3-го потока
int maxX, maxY; // Размеры экрана
HDC memdc; // DC виртуального окна
HBITMAP hbit; // Растр - это виртуальное окно
HBRUSH hbrush; // Дескриптор кисти
PROCESS_INFORMATION pinfo[Procmax];
int WINAPI WinMain (HINSTANCE hThisInst,
HINSTANCE hPrevInst,
LPSTR lpszArgs,
int nWinMode)
{
HWND hwnd;
MSG msg;
WNDCLASS wcl;
HACCEL hAccel;
// Определить класс окна
wcl.hInstance=hThisInst; // Дескриптор приложения
wcl.lpszClassName=szWinName; // Имя класса окна
wcl.lpfnWndProc=WindowFunc; // Функция окна
wcl.style=0; // Стиль по умолчанию
wcl.hIcon=LoadIcon(NULL,IDI_APPLICATION); // Иконка
wcl.hCursor=LoadCursor(NULL,IDC_ARROW) ; // Курсор
wcl.lpszMenuName="MYMENU"; // Меню
wcl.cbClsExtra=0; // Без дополнительной
wcl.cbWndExtra=0; // информации
// Определить заполнение окна белым цветом
wcl.hbrBackground=
(HBRUSH)GetStockObject(WHITE_BRUSH);
if(!RegisterClass(&wcl)) // Зарегистр. класс окна
return 0;
// Создать окно
hwnd=CreateWindow(szWinName, // Имя класса
"Порождение процессов и потоков",
WS_OVERLAPPEDWINDOW,// Стиль окна
CW_USEDEFAULT, // Х-координата
CW_USEDEFAULT, // Y-координата
CW_USEDEFAULT, // Ширина окна
CW_USEDEFAULT, // Высота окна
HWND_DESKTOP, // Нет родит. окна
NULL, // Нет меню
hThisInst, // Дескрип. приложения
NULL); // Без дополит. аргументов
// Загрузить акселераторы
hAccel=LoadAccelerators(hThisInst,"MYMENU");
ShowWindow(hwnd,nWinMode) ; // Показать окно и
UpdateWindow(hwnd); // перерисовать содержимое
// Запустить цикл обработки сообщений
while(GetMessage (&msg,NULL,0,0))
if(!TranslateAccelerator(hwnd,hAccel,&msg))
{
TranslateMessage(&msg); // Использ.Клавиатуры
DispatchMessage (&msg); // Возврат к Windows
}
return msg. wParam;
}
// Следующая функция вызывается операционной системой
// Windows и получает в качестве параметров сообщения
// из очереди сообщений данного приложения
LRESULT CALLBACK WindowFunc(HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT paintstruct;
TEXTMETRIC tm;
STARTUPINFO startin;
switch(message)
{
case WM_CREATE: // Получаем размеры экрана
maxX=GetSystemMetrics(SM_CXSCREEN);
maxY=GetSystemMetrics(SM_CYSCREEN);
hdc=GetDC(hwnd); // Совмест. с окном растр
memdc=CreateCompatibleDC(hdc);
hbit=CreateCompatibleBitmap(hdc,maxX,maxY);
SelectObject(memdc,hbit);
hbrush=(HBRUSH)GetStockObject(WHITE_BRUSH);
SelectObject(memdc,hbrush);
PatBlt(memdc,0,0,maxX,maxY,PATCOPY);
ReleaseDC(hwnd,hdc);
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_PROCESS:
if(procnum == Procmax)
{
MessageBox(hwnd,
"Нельзя создать больше",
"Ошибка", MB_OK);
break;
} // Не более чем Procmax
// Получить метрики текста */
GetTextMetrics(memdc, &tm);
sprintf(str, "Порождается процесс %d",
procnum);
TextOut(memdc, X, Y, str, strlen(str));
Y = Y+tm.tmHeight+tm.tmExternalLeading;
InvalidateRect(hwnd,NULL,1); //Сообщить
// Порождение нового процесса
startin.cb=sizeof(STARTUPINFO);
startin.lpReserved = NULL;
startin.lpDesktop = NULL;
startin.lpTitle = NULL;
startin.dwFlags =STARTF_USESHOWWINDOW;
startin.cbReserved2 = 0;
startin.lpReserved2 = NULL;
startin.wShowWindow = SW_SHOWMINIMIZED;
CreateProcess(NULL, "Test.exe", NULL,
NULL, FALSE, 0, NULL,
NULL, &startin,
&(pinfo[procnum]));
procnum++;
break;
case ID_KILLPROC:
if(procnum)
procnum--;
else
{
MessageBox(hwnd,
"Больше процессов нет",
"Ошибка", MB_OK);
break;
}
// Получить метрики текста
GetTextMetrics(memdc, &tm);
TerminateProcess
(pinfo[procnum].hProcess, 0);
sprintf(str, "Процесс %d завершен",
procnum);
TextOut(memdc, X, Y, str, strlen(str));
Y = Y+tm.tmHeight+tm.tmExternalLeading;
InvalidateRect(hwnd,NULL,1); //Сообщить
break;
case ID_THREAD:
CreateThread
(NULL, 0,
(LPTHREAD_START_ROUTINE)MyThread1,
(LPVOID)NULL, 0, &Tid1);
CreateThread
(NULL, 0,
(LPTHREAD_START_ROUTINE)MyThread2,
(LPVOID)NULL, 0, &Tid2);
InvalidateRect(hwnd, NULL, 1);
break;
case ID_HELP:
MessageBox(hwnd,
"F2: Новый процесс\n"
"F3: Завершить процесс\n"
"F4: Новый поток",
"Помощь:", MB_OK);
InvalidateRect(hwnd,NULL,1); //Сообщить
break;
}
break;
case WM_PAINT: // Перерисовка окна
hdc=BeginPaint(hwnd,&paintstruct); // Пол. DC
// Теперь копируем растр из памяти на экран
BitBlt(hdc,0,0,maxX,maxY,memdc,0,0,SRCCOPY);
EndPaint(hwnd,&paintstruct); // Освободить DC
break;
case WM_DESTROY: // Завершение программы
DeleteDC(memdc); // Удалить виртуальное окно
PostQuitMessage(0);
break;
default:
// Все сообщения, не обрабатываемые в данной
// функции, направляются на обработку по
// умолчанию
return DefWindowProc(hwnd,message,
wParam,lParam);
}
return 0;
}
//
// Начало выполнения 1-го потока
//
DWORD MyThread1(LPVOID param)
{
int i;
DWORD curTid = Tid1;
TEXTMETRIC tm;
// Получить метрики текста
GetTextMetrics(memdc, &tm);
for(i=0; i<10; i++)
{
Sleep(500); // Задержка 0,5 сек
sprintf(str, "Поток %ld, сигнал %d", curTid, i);
TextOut(memdc, X, Y, str, strlen(str));
Y = Y + tm.tmHeight + tm.tmExternalLeading;
InvalidateRect((HWND)param, NULL, 1) ;
Beep(600, 250); // 600 Гц, 0,25 сек
}
return 0;
}
//
// Начало выполнения 2-го потока
//
DWORD MyThread2(LPVOID param)
{
int i;
DWORD curTid = Tid2;
TEXTMETRIC tm;
// Получить метрики текста
GetTextMetrics(memdc, &tm);
for(i=0; i<10; i++)
{
Sleep(200); // Задержка 0,20 сек
sprintf(str, "Поток %ld, сигнал %d", curTid, i);
TextOut(memdc, X, Y, str, strlen(str));
Y = Y + tm.tmHeight + tm.tmExternalLeading;
InvalidateRect((HWND)param, NULL, 1) ;
Beep(300, 250); // 300 Гц, 0,25 сек
}
return 0;
}
Рис. 12.3. Окно программы с индикацией двух потоков
Пример окна этой программы представлен на рис. 12.3. Из текста этой программы следует, что при создании нескольких потоков для каждого из них необходимо определить потоковую функцию и использовать отдельный вызов функции CreateThread(). Все потоки одного процесса выполняются параллельно. Это видно из последовательности вывода информационных строк в главном окне программы.
