Примерные действия по созданию потока

Каждый поток имеет свою функцию – функцию потока. Пока выполнение этой функции не завершено, поток продолжает оставаться выполняемым. Эта функция должна быть объявлена следующим образом(в качестве имени потоковой функции выберем ThreadFun):

void ThreadFun(void *lpvoid);
  • Поток, создающий другой поток, может передавать через параметр lpvoid создаваемому потоку информацию в виде 32-разрядной переменной. Обычно эта переменная является указателем на блок данных (например, на структуру данных) для хранения общих переменных для потоков. Это дает возможность создающему и создаваемому потокам совместно владеть информацией без использования глобальных переменных (общая память потоков).

Рассмотрим пример двухпотокового приложения, в котором главный поток создает окно приложения и отвечает за взаимодействие с пользователем, а вторичный поток после своего создания параллельно с работой главного потока постоянно выводит в окно приложения некоторое изображение.

Пусть созданием и остановкой потока, а также типом выполняемого потоком действия (видом рисунка), управляет пользователь при помощи команд меню, имеющих идентификаторы:

#define IDM_CIRCLES 1 #define IDM_BARS 2 #define IDM_STOP 3 #define IDM_BEGIN 4

Создадим описание структуры, используемой для хранения общих переменных создающего (в данном случае, главного) потока и создаваемого (вторичного) потока:

struct PARAM { BOOL type; // тип выполняемого потоком действия HWND wnd; // окно, в оконной процедуре которого создается поток BOOL stop; // признак завершения работы потока };

Рассмотрим оконную процедуру, обрабатывающую сообщения для окна, созданного главным потоком. В этой оконной функции создадим вторичный поток, выполняющийся параллельно с главным потоком:

LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { static struct PARAM p; // используется как общая память потоков . . . switch(msg) { case WM_COMMAND: // обработка сообщений от меню { switch(LOWORD(wParam)) { case IDM_BEGIN: // запуск потока на выполнение { // запись в общую память потоков, p.type=0; p.wnd=hWnd; p.stop=0; // создание и немедленный запуск потока _beginthread(ThreadFun,0,(void *)(&p)); }; break; case IDM_STOP: // полная остановка потока { // записать признак завершения потока p.stop=1;}; break; case IDM_CIRCLES: // изменить тип действия { // записать тип выполняемого потоком действия p.type=0;}; break; case IDM_BARS: // изменить тип действия { // записать тип выполняемого потоком действия p.type=1;}; break; } };return 0l; case WM_DESTROY: { // записать признак завершения потока p.stop=1; PostQuitMessage(0); }; return 0l; // обработка других сообщений . . . default: return DefWindowProc(hWnd, msg, wParam, lParam); } return 0l; }

Функция создаваемого вторичного потока в данном случае может иметь следующее определение:

void ThreadFun(void *lpvoid) { // автоматические переменные потока . . . // получение адреса общей памяти потоков struct PARAM *p=(struct PARAM *)lpvoid; while(!p->stop) // пока признак завершения не установлен { // выполнение действия, определяемогоp->type, при этом может // использоваться дескриптор создавшего поток окна, он хранится в p->wnd . . . Sleep(1000); // задержка на 1 сек } _endthread(); // полная остановка потока }

Созданный по команде меню вторичный поток будет выполняться до тех пор, пока приложение не завершит свою работу, или пока пользователь не остановит поток при помощи соответствующей команды меню.