|
Программирование >> Структура ядра и системные вызовы
/* ожидать завершения потока чтения */ if (! thrjoin (rtid, Stid, 0)) done = 1; cond signal(scondx); /* удаление блокировки */ mutex destroy(smutx); cond destroy(scondx); thr exit(0); return 0; Функция main инициализирует взаимоисключающую блокировку mutx и условную переменную condx. Затем она создает поток записи и поток чтения для выполнения функций writer и reader. После этого главный поток ждет, пока поток чтения завершится с помощью функции thr Join, и сигнализирует потоку записи о необходимости завершения посредством глобальной переменной done. По завершении потоков чтения и записи главный поток удаляет взаимоисключающую блокировку и условную переменную (функциями mutexjdestroy и conddestroy соответственно). Поток чтения читает одну или несколько строк, введенных пользователем со стандартного устройства ввода. Для каждой прочитанной строки он сначала устанавливает взаимоисключающую блокировку, чтобы иметь возможность доступа к глобальным переменным msgbuf и msglen. Если блокировку удается установить, поток помещает пользовательское сообщение в массив msgbuf и присваивает переменной msglen значение, равное длине текста сообщения. Затем с помощью функций condsignal и mutexjunlock поток передает записывающему процессу сигнал о том, что нужно проверить переменную msglen. Поток чтения завершается, если не может прочитать введенный пользователем текст. В этом случае он снимает взаимоисключающую блокировку и самозавершается с помощью функции thr exit. Поток записи непрерывно опрашивает глобальную переменную msglen. Если ее значение не равно нулю, значит в массиве msgbuf есть сообщение, которое можно направить на стандартное устройство вывода. Для обработки каждого сообщения поток предварительно устанавливает взаимоисключающую блокировку, чтобы обеспечить себе исключительный доступ к переменным msglen и msgbuf В случае успеха поток записи блокирует вызов функции condwait до тех пор, пока поток чтения или главный поток не вызовет функцию condsignal для разблокирования этого вызова. После разблокирования поток записи проверяет, имеет ли переменная done ненулевое значение. Если имеет, то главный поток посылает в поток записи сигнал выхода. Если переменная done равна нулю, а значение переменной msglen не равно нулю, поток направляет сообщение, содержащееся в msgbuf, на стандартное устройство вывода. В противном случае он возвращается в цикл вызова condjwait и ожидает поступления сообщения. Когда поток записи блокируется в вызове condwait, взаимоисключающая блокировка mutx снимается. чтобы ее мог установить поток чтения или главный поток. Когда поток чтения или главный поток вызывает для переменной condx функцию condsignal, функция condwait, прежде чем разблокировать поток записи, автоматически устанавливает взаимоисключающую блокировку. Ниже приведен пример запуска программы pipe. С и полученные результаты: % СС pipe.с -Ithread -о pipe % pipe . Have а good day *>Have a good day Bye-Bye *>Вуе-Вуе 5 exits 4 exits 13.5.2.3. Условные переменные стандарта POSIX.Ic Ниже приведены API POSIX.Ic для управления условными переменными и соответствующие API Sun.
Прототипы этих функций выглядят следующим образом: #include <pthread.h> int pthread cand init{pthTead cond t* condp, pthread condatt t* attr); int pthread cand wait(pthTead cond t* condp, pthread niutex t* mutxp); int pthread candjtimedwait (pthread cond t* condp, pthread mutex t* mutxp, struct timespec* timp); int pthread cand signal (pX\\xea6 cond t* condp); int pthread cand braadcast (pthread cond t* condp); int pthreadjcandjdestray (pthread cond t* condp); Значение аргумента condp представляет собой адрес переменной типа pthreadcondj. Эта переменная является ссылкой на выделенную условную переменную. Аргумент attr функции pthreadjcondjnit - указатель на объект, содержащий атрибуты, которые задают свойства условной переменной. Если эта переменная должна иметь свойства по умолчанию, значение аргумента attr равно нулю. По стандарту POSIX.lc условная переменная может инициализироваться статическим инициализатором PTHREAD COND INITIALIZER. Следующий код pthread cond t cond var; (void) pthread cond init(Scond var, 0); идентичен оператору pthread cond t cond var = PTHREAD COND INITIALIZER; API pthread cond wait, pthread cond timedwait, pthread cond signal, pthreai cond broadcastvipthread cond destroy имеют то же назначение, что и API Sun cond wait, condjimedwait, cond signal, cond broadcast и condjdestroy. Описание этих API приведено в разделе 13.5.2.1. 13.5.3. Блокировки чтения-записи фирмы Sun Блокировки чтения-записи подобны взаимоисключающим блокировкам, но могут устанавливаться как только для чтения, так и только для записи. Один или несколько потоков могут одновременно устанавливать блокировку Чтения. Поток, который желает установить блокировку записи, будет заблокирован до тех пор, пока не будут сняты все блокировки чтения. Если поток устанавливает блокировку записи, ни один другой поток не может установить блокировку чтения или блокировку записи на данную блокировку до тех пор, пока предыдущий поток не снимет свою блокировку записи. Если два потока одновременно пытаются установить блокировку - один для чтения, другой для записи,- то предоставляется блокировка записи. Блокировки чтения-записи не так эффективны, как взаимоисключающие блокировки, но позволяют обеспечить одновременный доступ к данным для чтения нескольким процессам. В стандарте POSIX.lc блокировки чтения-записи не определены; они присутствуют только в системах фирмы Sun. Ниже приведены многопотоковые библиотечные функции Sun для управления блокировками чтения-записи. Функция Назначение rw init rw rdlock rw tryrdlock rw wrlock rw trywrlock rw unlock rw destroy Инициализирует блокировку чтения-записи Устанавливает блокировку чтения Устанавливает блокировку чтения (вызывающий поток не блокируется) Устанавливает блокировку записи Устанавливает блокировку записи (вызывающий поток не блокируется) Снимает блокировку чтения-записи Удаляет блокировку чтения-записи I Прототипы этих функций выглядят следующим образом: #include <thread.h> int nv /W/f (rwlock t* rwp, int type, void* argp); int rw rdlock (rwlock t* rwp); int rwjtryrdlock (rwlock t* rwp); int nv.nr/oc/r(rwlock t* rwp); int rwjtrywriock (rwlock t* rwp); int rw unlock (rwlock t* rwp); int rwjdestroy (rwlock t* rwp); Значение аргумента rwp представляет собой адрес переменной типа rwlockj. Эта переменная является ссылкой на блокировку чтения-записи и устанавливается посредством функции rw init. Аргумент type функции rw init показывает, доступна ли данная блокировка чтения-записи для других процессов. Он может принимать следующие значения:
Аргумент argp функции rwjnit в настоящее время не задействуется. Его значение должно быть равно 0. Функция rw rdlock пытается установить блокировку чтения, указанную аргументом rwp. Она блокирует вызывающий поток до успешного завершения операции. Функция rwjryrdlock аналогична функции rw rdlock, но она неблокирующая. Если эта функция прерывается из-за того, что затребованная блокировка уже установлена как блокировка записи другим потоком, то возвращается ненулевое значение, а егто устанавливается в значение EBUSY. Функция rw wrlock пытается захватить блокировку записи, указанную аргументом rwp. Она блокирует вызывающий поток до успешного завершения операции. Функция rwjrywrlock аналогична функции rw wrlock, но она неблокирующая. Если эта функция прерывается из-за того, что затребованная блокировка принадлежит другому потоку, то возвращается ненулевое значение, а егто устанавливается в значение EBUSY. Функция rwjunlock снимает блокировку чтения-записи, заданную аргументом nvp, а функция rw destroy уничтожает ее. Приведенная ниже программа pipe2.C - это новая версия программы pipe. С яз предьщущего раздела. Для синхронизации потоков чтения и записи в новой программе вместо взаимоисключающей блокировки и условной переменной использована блокировка чтения-записи. finclude <iostream.h> finclude <thread.h> finclude <string.h> finclude <stdio.h> finclude <signal.h> rwlock t rwlk; int msglen, done = 0; char msgbuf[256]; void* writer (void* argp ) ( while (Idone) { if (tw rdlock(Srwlk)) perror( rw rdlock ); /* установить блокировку чтения */ if (msglen) { проверить завершение сообщения cout *> << msgbuf << endl; вывести сообщение msglen =0; , , if (rw unlock(&rwlk-)4%error ( rw unlock (1) ) снять : , блокировку Д3,.чтения- записи */ /* передать другому потоку */ thr yield О ; /* завершить поток */ cerr write thread ( (int)thr self() ) exitsXn ; thr exit(0); return 0; void* reader (void* argp ) { do { if (rw wrlock(srwlk)) perror( rw wrlock ); /* установить блокировку записи */ if (Imsglen) { буфер пуст? if (!cin.getlihe(msgbuf,256)) break; /* получить сообщение от . .ГкЭ. . /v, пользователя ♦/ msglen * strlen(msgbuf)+1;, установить размер сообщения if (rw urilock(Srwlk)) perror( rwunlock(2) ); /* снять блокировку чтения-записи */ thr yield(); передать другому потоку } while (1);,м - , . /* завершить поток */ cerr read thread ( (int)thr self() if (rw unlock(Srwlk)) perror( rw unlock(3) ); thr exit(0); return 0; ) exitsXn ; mainO { thread t wtid, rtid, tid; if (rwlock init(Srwlk, USYNC PROCESS, 0)) ( perror( rwlock ihit ); return 1; I* создать поток записи */ if (thr create(0,0,writer,0,0,swtid)) perror( thr create ); /* создать поток чтения */ if (thr create (0,0, reader. О, О, SrtidJ l,., perror( thr create ); /* ожидать завершения процесса чтения */ if (! thrjoin (rtid, stid, 0)) done = 1; /* очистка */ rwlock destroy(Srwlk); thr exit.(0) ; Функция main инициализирует блокировку чтения-записи, а затем создает потоки чтения и записи для совместной работы. Главный поток ждет завершения потока чтения, а затем через переменную done посылает в поток записи сигнал завершения. Затем главный поток удаляет блокировку чтения-записи и завершается. Поток чтения вьшолняет функцию read. Она получает от пользователя одну или несколько строк текста и для каждой введенной строки устанавливает блокировку чтения-записи для доступа с целью записи, обеспечивая потоку исключительное право доступа к переменным msgbuf тл msglen. После установки блокировки записи поток записывает текст сообщения в массив msgbuf записывает в msglen размер текста сообщения и снимает блокировку чтения-записи. Затем данный поток передает выполнение потоку записи, чтобы последний получил доступ к блокировке и переменной msgbuf. Затем поток берет следующее пользовательское сообщение и повторяет всю
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |