Процессы, потоки и нити в ОС Windows, страница 2

            cout<<"Master: Exiting\n";

            exit(0);

}

Листинг 3  Slave

#include <windows.h>

#include <iostream.h>

#include <stdio.h> // temp

void main(int argc,char *argv[])

{

            if (argc!=2)

            {

                        cerr<<"Slave: Запустите  MASTER.EXE\n";

                        exit(1);

            }

            int pid=atoi(argv[1]);

            HANDLE process=OpenProcess(PROCESS_QUERY_INFORMATION|SYNCHRONIZE,FALSE,pid);

            if (!process) cout<<"Slave: Ошибка при открытии процесса\n";

            cout<<"Slave: Подождите завершения работы МАСТЕРА\n";

            cout.flush();

            if (WaitForSingleObject(process,INFINITE)==STATUS_WAIT_0)

                        cout<<"Slave: МАСТЕР  завершил работу\n";

            else

                        cout<<"Slave: Неизвестная ошибка\n";

            exit(0);

}

На рис. 1 показана работа программы (запускается мастер).

Рис.1. Работа программы master.exe


Потоки

Листинг 4. Эта простая программа выводит на экран простое диалоговое окно с текстовым сообщением и при этом каждую секунду издает короткий звуковой сигнал, Для воспроизведения этого сигнала используется отдельный программный поток.

Листинг 4. Тревога!

#include <windows.h>

#include <process.h>  // необходимо для обращения к _beginthread

HANDLE mainthread;

void beepthread(void *)

{

DWORD xitcode;

while (GetExitCodeThread(mainthread,&xitcode)&&xitcode==STILL_ACTIVE)

{

MessageBeep(-1);

Sleep(1000);

}

}

void main()

{

mainthread=GetCurrentThread();

_beginthread(beepthread,0,NULL);

MessageBox(NULL,"Red Alert","Alert",MB_OK);

}

Основная программа сохраняет дескриптор потока в глобальной переменной. Это позволяет потоку, воспроизводящему звук, определить момент, когда основная программа завершит свою работу. В этот момент поток, воспроизводящий звук, также завершит свою работу. На рис. 2 показана работа программы.

Рис. 2. Работа программы ТРЕВОГА


Локальная память потоков

Иногда бывает удобно использовать некоторую область памяти, которая относится к конкретному потоку, но не является локальной переменной. Представьте, что вы разрабатываете сетевой сервер. Каждый из клиентов сервера обслуживается отдельным потоком. Чтобы выполнить некоторое действие от имени клиента, потоки обращаются к некоторой функции (допустим, ее имя — DoWork). Существуют причины, по которым вы хотите ограничить количество обращений каждого из клиентов к этой функции. Допустим, каждый из клиентов (а следовательно, каждый из потоков) имеет право обратиться к этой функции не более 10 раз.

Каким образом вы можете организовать подобный счетчик обращений? Глобальная переменная не подходит. Если вы используете глобальную переменную, ее значение будет увеличиваться каждый раз при обращении любого потока к функции DoWork. Таким образом, если десять потоков обратятся к этой функции по одному разу, значение счетчика станет равным 10, а это не то, что нам нужно. Локальная переменная тоже не подходит, так как при каждом очередном обращении к функции DoWork локальной переменной будет присваиваться нулевое значение.

Конечно, проблему можно решить несколькими способами. Например, каждый поток может выделить специальную область памяти, принадлежащую лично ему и каждый раз при обращении к DoWork передавать этой функции указатель на эту область в качестве аргумента. Возможно, этот способ подойдет для решения конкретно данной проблемы, однако, если вам потребуется несколько подобных переменных, вы можете столкнуться с новыми проблемами.