|
Программирование >> Структура ядра и системные вызовы
функция pthread sigmask устанавливает сигнальную маску вызывающего потока. Аргумент sigsetp содержит один или несколько номеров сигналов, применяемых к вызывающему потоку. Аргумент mode показывает, как следует использовать сигнал (сигналы), заданный в аргументе sigsetp. Возможные значения аргумента mode объявляются в заголовке <signal.h>: Значение аргумента mode Смысл SIG BLOCK SIG UNBLOCK SIG SETMASK Добавляет сигнальЕ, указанные в аргументе sigsetp, в сигнальную маску потока Удаляет сигналы, указанные в аргументе sigsetp, из сигнальной маски потока Заменяет сигнальную маску потока сигналом (или сигналами), указанным в аргументе sigsetp Если аргумент sigsetp имеет значение NULL, значение аргумента mode игнорируется. Значением аргумента oldsetp лопжт быть адрес переменной типа sigsetj*, в которой возвращается старая сигнальная маска. Если значение аргумента oldsetp - NULL, то старая сигнальная маска не возвращается. Функция pthreadjiill посылает сигнал, заданный аргументом signum, в поток, идентификатор которого задан аргументом tid. Передающий и принимающий потоки должны находиться в одном процессе. Ниже приведен пример программы, которая добавляет сигнал SIGINT в сигаальную маску потока, а затем посылает сигнал SIGTERM в поток с идентификатором 15: sigset t set, oldset; .sigemptyset(Sset); sigaddset(&set, SIGINIT); if (pthread setmask(SIG BLOCK, Sset, Soldset)) perror( pthread sigsetmask ); if (pthread kill(thread t)15, SIGTERM)) perror( pthredd kill ); 13.4.4. Функция sched yleld Ниже приведен прототип функции sched yield. #include <pthread.h> . int sched yield (void); Поток вызывает функцию sched yield, чтобы передать выполнение другим потокам с таким же приоритетом. При успешном выполнении данная функция возвращает О, а в случае неудачи - -1. Этот API стандарта POSIX. 1с эквивалентен API thr yield фирмы Sun. 13.5. Объекты синхронизации потоков выполнения Потоки выполнения в процессе совместно используют то же адресное пространство, что и процесс. Это значит, что все глобальные и статические переменные процесса доступны для всех его потоков. Чтобы обеспечить безошибочное манипулирование этими переменными, потоки должны как-то синхронизировать свою работу. В частности, ни один поток не должен обращаться к переменной, значение которой в текущий момент изменяется другим потоком, и ни один поток не может изменять значение переменной в то время, когда его читают другие потоки. Синхронизация нужна и тогда, когда два и более потока выполняют операции с общим потоком ввода-вывода. Например, если два потока выполнения одновременно записывают информацию в поток вывода, то невозможно предсказать, какие именно данные попадут в этот поток. Аналогичная проблема возникает при одновременном чтении данных из потока ввода. Чтобы разрешить проблемы синхронизации. Sun и POSIX. 1с предлагают для управления операциями, которые производят потоки выполнения над общими данными и потоками ввода-вывода в процессе, использовать следующие объекты: взаимоисключающие блокировки; условные переменные; семафоры. Самые примитивные и самые эффективные из этих объектов - взаимоисключающие блокировки. Они применяются для организации последовательного доступа к общим данным и выполнения сегментов кода. Второй по эффективности объект - условные переменные. Как правило, они используются с взаимоисключающими блокировками для управления асинхронным доступом к общим данным. Семафоры более сложны, нежели взаимоисключающие блокировки и условные переменные. Они используются почти так же, как семафоры UNIX System V и POSIX.Ib. Помимо этих средств. Sun предлагает еще один инструмент синхронизации потоков выполнения - блокировки чтения-записи. Такие блокировки обеспечивают множественный доступ для чтения и однократный доступ для записи к любым общим данным. Перечисленные выше объекты такой способностью не обладают. Блокировки чтения-записи используются прежде всего для защиты данных, которые часто читаются многими потоками, но редко изменяются. Процессы, которые применяют какие-либо объекты синхронизации, должны определить для них область памяти в своем виртуальном адресном пространстве. Если эти объекты определяются в общих областях памяти, которые доступны для многих процессов, их можно использовать для синхронизации потоков выполнения в этих процессах. Рассмотрим объекты синхронизации подробнее. 13.5.1. Взаимоисключающие блокировки Взаимоисключающие блокировки позволяют организовать выполнение потоков так, что когда несколько потоков пытаются установить такую блокировку, успеха достигает только один из них, который и продолжает выполняться. Остальные потоки блокируются до тех пор, пока эта блокировка не будет снята потоком-владельцем. При снятии взаимоисключающей блокировки невозможно предсказать, какой ожидающий поток будет следующим владельцем блокировки. В приведенной ниже таблице представлены API взаимоисключающих блокировок, разработанные фирмой Sun, а также API взаимоисключающих блокировок стандарта POSIX.lc. API Sun API POSIX.lc mutexjnit mutex destroy mutex lock mutex trylock mutex unlock pthread mutex init pthread mutex destroy pt h read m utex lock pthread mutex trylock pt h read m utex un lock Эти API более подробно рассматриваются ниже. 13.5.1.1. Взаимоисключающие блокировки Sun Фирма Sun использует для операций с взаимоисключающими блокировками следующие многопотоковые библиотечные функции: Функция Назначение mutex init Инициадизирует взаимоисключающую блокировку mutex lock Устанавливает взаимоисключающую блокировку mutex unlock Снимает взаимоисключающую блокировку mutex trylock Как mutexjock, только неблокирующая mutex destroy Удаляет взаимоисключающую блокировку Эти функции имеют следующие прототипы: #include <thread.h> int mutexjnit (mutex t* mutxp, int type, void* argp); int mutexjock (mutex t* mutxp); int mutexjrylock (mutex t* mutxp); int mutexjunlock (mutex t* mutxp); int mutexjdestroy (mutex t* mutxp); Значение аргумента mutxp - адрес переменной типа mutexj. Эта переменная определяется вызывающим потоком и устанавливается как ссылка на взаимоисключающую блокировку с помощью функции mutexjnit. Аргумент type функции mutexjnit показива&т, доступна ли данная блокировка для потоков в других процессах. Ниже приведены его возможные значения: Значение аргумента type Смысл USYNC PROCESS USYNC THREAD Взаимоисключающая блокировка может использоваться потоками в других процессах Взаимоисключающая блокировка может использо-ваться потоками только в вызывающем процессе Аргумент argp функции mutexjnit в настоящее время не задействуется, поэтому его значение должно быть равно 0. В процессе взаимоисключающая блокировка инициализируется только один раз и удаляется функцией mutex destroy. Взаимоисключающая блокировка устанавливается потоком с помощью функции mutexjock, а снимается функцией mutexjinlock. Функция mutexjock блокирует вызывающий поток, если взаимоисключающая блокировка уже установлена другим потоком. Когда эта взаимоисключающая блокировка снимается, поток разблокируется и после этого может стать владельцем новой блокировки. Функция mutextrylock отличается от функции mutexjock тем, что, если затребованной блокировкой уже владеет другой поток, функция возвращает в вызывающий поток код ошибки, но не блокирует его. 13.5.1.2. Взаимоисключающие блокировки POSIX.lc API для операций со взаимоисключающими блокировками, предусмотренные в стандарте POSIX.lc, похожи на соответствующие API Sun: Функция Назначение pthread mutex init pthread mutex lock pthread mutex unlock pthread mutex trylock pthread mutex destroy Инициализирует взаимоисключающую блокировку Устанавливает взаимоисключающую блокировку Снимает взаимоисключающую блокировку Как mutexjock, только неблокирующая Удаляет взаимоисключающую блокировку Эти функции имеют следующие прототипы: #include <pthread.h> int int int int int pttvread mutexjnit (pthreadmutext* mutxp, pthread mutexattr t* aWrp); pthreadjnutexjock (pthread mutex t* mutxp); pthread mutexJrylock (pthread mutex t* mutxp); pthread mutex unlock (pthread mutex t* mutxp); pthread mutex destroy (pthread mutex t* mutxp); Значение аргумента mutxp - адрес переменной типа pthread mutex t. Эта переменная определяется вызывающим потоком и устанавливается как ссылка на взаимоисключающую блокировку с помощью функции pthread mutex init. Аргумент attrp - это указатель на объект, содержащий атрибуты для новой взаимоисключающей блокировки. В качестве альтернативы вызову pthread mutex init может использоваться статический инициализатор PTHREAD MUTEX INITIALIZER. Таким образом, следующий код pthread mutex t lockx; (void)pthread mutex init(&1оскх, 0); идентичен оператору pthread mutex t lockx = PTHREAD MUTEX INITIALIZER; Синтаксис вызова и назначение функций pthreadmutexjock, pthread mutexjrylock, pthread mutex unlock, pthread mutex destroy такие же, как и у API Sun mutexlock, mutexjrylock, mutexjunlock и mutex destroy. 13.5.1.3. Примеры взаимоисключающих блокировок Показанная ниже функция printmsg может вызываться любым потоком для отображения сообщений на стандартном устройстве вывода. Она гарантирует вывод сообщений потоков по одному. Функция main - это пример приложения, тестирующего функцию printsmg: #include <stdio.h> #include <iostream.h> #include <thread.h> static mutex t lockx; определить переменную для блокировки void* printmsg (void* msg ) /* установить блокировку */ if (mutex lock(Slockx)) perror( mutex lock ); else { /* вывести сообщение */ cout, (char*)msg endl << flush; /* снять блокировку */ if (mutex unlock (&lockkFf%errof ( mutex unlock >y return 0; int t ain(iBt argc, char* argv[]- /* инициализировать взаимоисключающую блокировку */ if (mutex init (Ыоскх, USYNC THREAD,NULL) ) perror( mutex lock ); /* создать потоки, которые вызывают printmsg */ while (-argc > 0) i ; - if (thr create(0,0,printmsg,argv[argc],0, 0)) perror( thr create ); /* ждать завершения всех потоков */ while (!thr join(0,0,0)) ; /* удалить взаимоисключающую блокировку */ if Cmutex destroy(Slockx)) perror( mutex destroy ); return 0,- Функция main в этом примере инициализирует взаимоисключающую блокировку lockx, которой будут пользоваться все потоки в этом процессе. Затем функция создает несколько потоков - по одному для каждого аргумента командной строки,- которые будут вызывать функцию printmsg и отображать на стандартном устройстве вывода строки аргументов команд. Количество потоков, одновременно вызывающих функцию printmsg, не имеет значения, потому что эта функция будет обслуживать потоки по одному. Ниже приведены пример запуска и результаты работы программы printmsg. С: % СС printmsg.с -Ithread -о printmsg % printmsg 1 2 3 А теперь рассмотрим еще один пример - класс globdat, определяющий тип данных для переменных, к которым одновременно могут обращаться несколько потоков. Этот класс определяется в заголовке globdat.h: tifndef GLOB DAT H fdefine GLOB DAT н tinclude <thread.h> tinclude <iostream.h> tinclude <stdio;h> class glob dat private: ,), int mutex t val; lockx; iisublic: { I* функция-конструктор */ 4.glob dat( int a ) :,..< { .val = a; d:, if (mutexifiit (slockx, USYNC THREAD, 0)) perror( mutex init ); /* функция-деструктор */
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |