Вход/Регистрация
Программирование для Linux. Профессиональный подход
вернуться

Самьюэл Алекс

Шрифт:

Чтобы создать исключающий семафор, нужно объявить переменную типа

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

pthread_mutex_t mutex;

pthread_mutex_init(&mutex, NULL);

Более простой способ создания исключающего семафора со стандартными атрибутами — присвоение переменной специального значения

PTHREAD_MUTEX_INITIALIZER
. Вызывать функцию
pthread_mutex_init
в таком случае не требуется. Это особенно удобно для глобальных переменных (а в C++ — статических переменных класса). Предыдущий фрагмент программы эквивалентен следующей записи:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

Поток может попытаться захватить исключающий семафор, вызвав функцию

pthread_mutex_lock
. Если семафор свободен, он переходит во владение данного потока и функция немедленно завершается. Если же семафор уже был захвачен другим потоком. выполнение функции
pthread_mutex_lock
блокируется и возобновляется только тогда, когда семафор вновь становится свободным. Сразу несколько потоков могут ожидать освобождения исключающего семафора. Когда это событие наступает, только один поток (выбираемый произвольным образом) разблокируется и получает возможность захватить семафор; остальные потоки остаются заблокированными.

Функция

pthread_mutex_unlock
освобождает исключающий семафор. Она должна вызываться только из того потока, который захватил семафор.

В листинге 4.11 представлена другая версия программы, работающей с очередью заданий. Теперь очередь "защищена" исключающим семафором. Прежде чем получить доступ к очереди (для чтения или записи), каждый поток сначала захватывает семафор. Только когда вся последовательность операций проверки очереди и удаления задания из нее будет закончена, произойдет освобождение семафора. Благодаря этому не возникает описанное выше состояние гонки.

Листинг 4.11. (job-queue2.c) Работа с очередью заданий, защищенной исключающим семафором

#include <malloc.h>

#include <pthread.h>

struct job {

 /* Ссылка на следующий элемент связанного списка. */

 struct job* next;

 /* Другие поля, описывающие требуемую операцию... */

};

/* Список отложенных заданий. */

struct job* job_queue;

/* Исключающий семафор, защищающий очередь. */

pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;

/* Обработка заданий до тех пор, пока очередь не опустеет. */

void* thread_function(void* arg) {

 while (1) {

struct job* next_job;

/* Захват семафора, защищающего очередь. */

pthread_mutex_lock(&job_queue_mutex);

/* Теперь можно проверить, является ли очередь пустой. */

if (job_queue == NULL)

next_job = NULL;

else {

/* Запрашиваем следующее задание. */

next_job = job_queue;

/* Удаляем задание из списка. */

job_queue = job_queue->next;

}

/* Освобождаем семафор, так как работа с очередью окончена. */

pthread_mutex_unlock(&job_queue_mutex);

/* Если очередь пуста, завершаем поток. */

if (next_job == NULL)

break;

/* Выполняем задание. */

process_job(next_job);

/* Очистка. */

free(next_job);

 }

 return NULL;

}

Все операции доступа к совместно используемому указателю

job_queue
происходят между вызовами функций
pthread_mutex_lock
и
pthread_mutex_unlock
. Объект задания, ссылка на который хранится в переменной
next_job
, обрабатывается только после того, как ссылка на него удаляется из очереди, что позволяет обезопасить этот объект от других потоков.

Обратите внимание на то, что, если очередь пуста (т.е. указатель

job_queue
равен
NULL
), цикл не завершается немедленно. Это привело бы к тому, что исключающий семафор так и остался бы в захваченном состоянии и не позволил бы ни одному другому потоку получить доступ к очереди заданий. Мы действуем иначе: записываем в переменную
next_job
значение
NULL
и выходим из цикла только после освобождения семафора.

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

  • Читать дальше
  • 1
  • ...
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: