hStream [0] =CreateThread(NULL,0 , Stream l ,NULL,0 ,&dw
ID S tream l);
hStream [ 1 ] =CreateThread(NULL, 0, Stream2, NULL, 0, &dw
IDStream2);
/ / Создаем события дпя управления потоками
hEventsFromChild [ 0] =
CreateEvent(NULL,TRUE, FALSE,NULL);
hEventsFronC hild[1 ]=
C reateE vent(NULL, TRUE, FALSE,NULL);
hEventsAboutEnd[0 ]=
C reateE vent(NULL,TRUE, FALSE,NULL),-
hEventsAboutEnd [1] =
C reateE vent(NULL, TRUE, FALSE,NULL);
W a itF orM u ltip leO b jects(2 ,hEventsFromChild,TRUE,IN
F IN IT E );
SetE vent(hE ventToC hild[0] ) ;
S etE ven t(h E ven tT oC h ild [l]);
W aitForM ultipleO bj e c t s (2 ,hEventsAboutEnd,TRUE, IN-
FINITE) ; //ждем сообщений для прекращения
/ /работы потоков
bTerminate=TRUE;
W a itF orM u ltip leO b jects(2 ,hstream ,TRUE,INFINITE);
F o rfin t i= l;i< 2 ;i+ + ) {
/ / закрываем дескрипторы потоков и событий
C loseH an d le(h T h read s[i]);
C loseH andle(h E ven tsT oC h ild ti]);
C loseH andle(hE ventsFrom C hild[i])
;
)
//удаляем критическую секцию
D e le te C ritic a lS e c to in (& C ritS e c );
retu rn 0;
)
DWORD WINAPI Stream l (LPVOID)
{
SetEvent(hEventsFrom Child[0] ) ;// оповещаем, что
поток запущен
W a itF orS in gleO b jects(h E ven tsT oC h ild [0 ].IN F IN IT E );
// ждем разрешения на старт
W h ile( ! bTerm inate) {
E n te rC ritic a lS e c tio n (& C ritS e c );
// Обращение к защищаемым данным
// здесь можете вставить оператор выбора
//если вам уже не нужен поток, вызываем
//SerEvent(ShEventsAboutEnd[0]);
L e a v e C ritic a lS e c tio n (& C ritS e c );
)
retu rn 0;
)
DWORD WINAPI Stream2 (LPVOID)
{
SetE vent(hE ventsFrom C hild[0]) ; оповещаем, что поток
запущен
W aitForS in gleO bjects(h E ven tsT oC h ild tO ].IN F IN ITE );
/ / ждем разрешения на старт
W h ile( ! b T erm in ate){
E n te rC ritic a lS e c tio n (& C ritS e c );
// Обращение к защищаемым данным
// здесь можете вставить оператор выбора
//если вам уже не нужен поток, вызываем
//SerEvent(& hEventsAboutEnd[l]);
L e a v e C ritic a lS e c tio n (S C ritS e c );
)
retu rn 0;
}
Страш но © ? М не поначалу тоже было страшно, но потом
разобрался. Я привел ш аблон, который довольно часто
используется. В большинстве книг и справочников можно
найти похожие. Итак, в начале мы объявили все переменные,
прототипы функций, массивы дескрипторов, идентификаторы
и переменную типа
c r it ic a l _ s e c t io n .
В гпо/п-функции
создаем потоки, которые после создания сообщ ают, что они
готовы действовать. Затем мы останавливаем каждый поток
в ожидонии разрешения работать. В это время главный поток
проверяет, все ли потоки создоны и готовы к работе, после
чего дает команду «на старт». (Это делается для того, чтобы
синхронизировать запуск наших потоков. Ведь на создание
каждого потока требуется время. Время это мало, но система
в любой момент может выделить квант времени процессора
другой программе и, как следствие, получим, что один поток
уже роботает, а другой еще даже не создон.) Далее в функциях
потоков (после разрешения) выполняется доступ к запрещенным
данным. Если потоки выполнили свою работу, то посылаем
сообщение о прекращении работы. Реакцией на это будет
установка параметра
bTerm inate
в значение
true.
Ждем
заверш ения
работы
потоков,
после
чего
закры ваем
дескрипторы и критические секции. Еще один пример. Допустим,
у вас работает несколько потоков. Первый читает файл и
зописывает полученные данные в глобальные переменные,
оповещ ая спящие потоки, а сам хочет опять подготовку
следующей порции данных из другого файла, но буфер занят
предыдущей порцией, которую используют другие потоки.
Тогда первый поток засыпает, пока остальные потоки не
заверш ат операции. Второй из глобального буфера берет
данные, делает вычисления и полученные данные выводит на
экран, после чего пытается опять читать данные из глобального
буфера, но там находятся устаревшие данные. Поэтому второй
поток засыпает, пробуждая первый. И ток, циклически, может
выполняться
вся
програм м а.
В
таких
случаях
удобно
использовать события с автосбросом. Таких примеров можно
привести великое множество, а прогроммо может иметь такой
запутанный алгоритм работы, что без чаш ки пива не
разобраться © . Но все надо делать с умом. Не запутывайте
программу, не используйте события там, где это не является
необходимым. Код должен быть понятен и моксимально
упрощен (все гениальное просто).
О сем аф орах и м ью тексах умолчим, ибо мьютексы схожи
с критическими секциями, а семофоры отличаются от событий
наличием
счетчика.
В
следующий
раз
поговорим
об
использовании MFC. А пока сделайте программкам интерфейс.
(Продолжение следует)
Л
Окончание. Начало на стр. 39
происходит образование связи между щелчком на кнопке
(сигнал
c lic k e d (
) классо
QPushButton)
и слотом
b tn C lic k ().
Теперь рассмотрим метод
b tn ciick .
Здесь можно встре-
тить класс
QMessageBox
— функциональный анолог
Mes-
sageBox
из
winAPl.
При помощи статического метода клас-
са мы создаем информационное окош ко с заголовком «Вуе!»
и текстом «Exiting». Ну, а
c lo s e
() закрывает окно и завер-
шает выполнение программы.
МОЙ КОМПЬЮТ!
Осталось поработать над файлом проекта
h e llo .p ro .
Вот каким оброзом он должен теперь выглядеть
TEMPLATE = app
INCLUDEPATH += .
HEADERS += h e llo .h
SOURCES += h e llo , cpp main, cpp
Ну, а теперь стандартными
gmake
&&
make
компилируем
прогромму и запускаем на выполнение. Вот, что у нас долж-
но получиться — рисунок 1. При
щелчке на кнопке появляется вот
такое окош ко, — рисунок 2.
Если вам лень набирать листинг
прогроммы, то можете выкачать его
из И нтернета по ссылке http ://
linuxmk.nm.ru/hello2.zip
На этом я с вами прощаюсь. В
следующий раз будут рассмотрены
L a yo ut-классы, о также более «про-
двинутая» работа с gmake
предыдущая страница 41 Мой Компьютер 2005 09 читать онлайн следующая страница 43 Мой Компьютер 2005 09 читать онлайн Домой Выключить/включить текст