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

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

Жанры

Программирование для 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
.

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

Точка Бифуркации V

Смит Дейлор
5. ТБ
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Точка Бифуркации V

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

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

Память льда

Эриксон Стивен
3. «Малазанская империя»
Фантастика:
фэнтези
6.00
рейтинг книги
Память льда

Дерзкие побеги

Нестерова Дарья Владимировна
Документальная литература:
прочая документальная литература
5.00
рейтинг книги
Дерзкие побеги

Тихие ночи

Владимиров Денис
2. Глэрд
Фантастика:
фэнтези
боевая фантастика
попаданцы
5.00
рейтинг книги
Тихие ночи

Как прорастают зерна

Волкова Дарья
Любовные романы:
современные любовные романы
7.00
рейтинг книги
Как прорастают зерна

Виконт, который любил меня

Куин Джулия
2. Бриджертоны
Любовные романы:
исторические любовные романы
9.13
рейтинг книги
Виконт, который любил меня

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

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

Вернувшийся: Новая жизнь. Том I

Vector
1. Вернувшийся
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Вернувшийся: Новая жизнь. Том I

Я уже барон

Дрейк Сириус
2. Дорогой барон!
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Я уже барон

Матабар IX

Клеванский Кирилл Сергеевич
9. Матабар
Проза:
магический реализм
5.00
рейтинг книги
Матабар IX

Пески времени

Шелдон Сидни
Детективы:
триллеры
9.02
рейтинг книги
Пески времени

Эффект энтропии

Макинтайр Вонда Н.
2. Звездный путь
Фантастика:
эпическая фантастика
космическая фантастика
5.00
рейтинг книги
Эффект энтропии

Князь Целитель 5

Ткачев Андрей Юрьевич
5. Князь Целитель
Фантастика:
боевая фантастика
городское фэнтези
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Князь Целитель 5