Чтение онлайн

на главную - закладки

Жанры

Программирование для Linux. Профессиональный подход

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

Шрифт:

В Linux имеется функция

sem_getvalue
, позволяющая узнать текущее значение счетчика семафора. Это значение помещается в переменную типа
int
, на которую ссылается второй аргумент функции. Не пытайтесь на основании данного значения определять, стоит ли выполнять операцию ожидания или установки, так как это может привести к возникновению гонки: другой поток способен изменить счетчик семафора между вызовами функции
sem_getvalue
и какой-нибудь другой функции работы с семафором. Доверяйте только атомарным функциям
sem_wait
и
sem_post
.

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

Листинг 4.12. (job-queue3.c) Работа с очередью заданий с применением семафора

#include <malloc.h>

#include <pthread.h>

#include <semaphore.h>

struct job {

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

 struct job* next;

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

};

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

struct job* job_queue;

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

pthread_mutex_t job_queue_mutex =

 PTHREAD_MUTEX_INITIALIZER;

/* Семафор, подсчитывающий число гаданий в очереди. */

sem_t job_queue_count;

/* Начальная инициализация очереди. */

void initialize_job_queue {

 /* Вначале очередь пуста. */

 job_queue = NULL;

 /* Устанавливаем начальное значение счетчика семафора

равным 0. */

 sem_init(&job_queue_count, 0, 0);

}

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

void* thread_function(void* arg) {

 while (1) {

struct job* next_job;

/* Дожидаемся готовности семафора. Если его значение больше

нуля, значит, очередь не пуста; уменьшаем счетчик на 1.

В противном случае операция блокируется до тех пор, пока

в очереди не появится новое задание. */

sem_wait(&job_queue_count);

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

pthread_mutex_lock(&job_queue_mutex);

/* Мы уже знаем, что очередь не пуста, поэтому без лишней

проверки запрашиваем новое задание. */

next_job = job_queue;

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

job_queue = job_queue->next;

/* освобождаем исключающий семафор, так как работа с

очередью окончена. */

pthread_mutex_unlock(&job_queue_mutex);

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

process_job(next_job);

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

free(next_job);

 }

 return NULL;

}

/* Добавление нового задания в начало очереди. */

void enqueue_job(/* Передача необходимых данных... */) {

 struct job* new_job;

 /* Выделение памяти для нового объекта задания. */

 new_job = (struct job*)malloc(sizeof(struct job));

 /* Заполнение остальных полей структуры JOB... */

 /* Захватываем исключающий семафор, прежде чем обратиться

к очереди. */

 pthread_mutex_lock(&job_queue_mutex);

 /* Помещаем новое задание в начало очереди. */

 new_job->next = job_queue;

 job_queue = new_job;

 /* Устанавливаем семафор, сообщая о том, что в очереди появилось

новое задание. Если есть потоки, заблокированные в ожидании

семафора, один из них будет разблокирован и

обработает задание. */

 sem_post(&job_queue_count);

 /* Освобождаем исключающий семафор. */

 pthread_mutex_unlock(&job_queue_mutex);

}

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

Функция

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

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

Геном хищника. Книга девятая

Гарцевич Евгений Александрович
9. Я - Легенда!
Фантастика:
боевая фантастика
рпг
попаданцы
5.00
рейтинг книги
Геном хищника. Книга девятая

Черный Маг Императора 9

Герда Александр
9. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 9

Я снова не князь! Книга XVII

Дрейк Сириус
17. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я снова не князь! Книга XVII

Перекресток судеб

Щепетнов Евгений Владимирович
6. Нед
Фантастика:
фэнтези
8.84
рейтинг книги
Перекресток судеб

Меняя маски

Метельский Николай Александрович
1. Унесенный ветром
Фантастика:
боевая фантастика
попаданцы
9.22
рейтинг книги
Меняя маски

На границе империй. Том 5

INDIGO
5. Фортуна дама переменчивая
Фантастика:
боевая фантастика
попаданцы
7.50
рейтинг книги
На границе империй. Том 5

Слезы Эйдена 1

Владимиров Денис
11. Глэрд
Фантастика:
боевая фантастика
фэнтези
попаданцы
5.00
рейтинг книги
Слезы Эйдена 1

Я еще князь. Книга XX

Дрейк Сириус
20. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я еще князь. Книга XX

Звездная Кровь. Экзарх III

Рокотов Алексей
3. Экзарх
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Звездная Кровь. Экзарх III

Газлайтер. Том 40

Володин Григорий Григорьевич
40. История Телепата
Фантастика:
альтернативная история
аниме
попаданцы
5.00
рейтинг книги
Газлайтер. Том 40

В лапах зверя

Зайцева Мария
1. Звериные повадки Симоновых
Любовные романы:
остросюжетные любовные романы
эро литература
5.00
рейтинг книги
В лапах зверя

Легат

Прокофьев Роман Юрьевич
6. Стеллар
Фантастика:
боевая фантастика
рпг
6.73
рейтинг книги
Легат

Инкарнатор

Прокофьев Роман Юрьевич
1. Стеллар
Фантастика:
боевая фантастика
рпг
7.30
рейтинг книги
Инкарнатор

Сержант. Назад в СССР. Книга 4

Гаусс Максим
4. Второй шанс
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Сержант. Назад в СССР. Книга 4