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

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

Жанры

UNIX: взаимодействие процессов

Стивенс Уильям Ричард

Шрифт:

//mutex/prodcons6.c

46 void *

47 produce(void *arg)

48 {

49 for (;;) {

50 Pthread_mutex_lock(&put.mutex);

51 if (put.nput >= nitems) {

52 Pthread_mutex_unlock(&put.mutex);

53 return(NULL); /* массив заполнен, готово */

54 }

55 buff[put.nput] = put.nval;

56 put.nput++;

57 put.nval++;

58 Pthread_mutex_unlock(&put.mutex);

59 Pthread_mutex_lock(&nready.mutex):

60 if (nready.nready == 0)

61 Pthread_cond_signal(&nready.cond);

62 nready.nready++;

63 Pthread_mutex_unlock(&nready.mutex);

64 *((int *) arg) += 1;

65 }

66 }

67 void*

68 consume(void *arg)

69 {

70 int i;

71 for (i = 0; i < nitems; i++) {

72 Pthread_mutex_lock(&nready.mutex);

73 while (nready.nready == 0)

74 Pthread_cond_wait(&nready.cond, &nready.mutex);

75 nready.nready--;

76 Pthread_mutex_unlock(&nready.mutex);

77 if (buff[i] != i)

78 printf("buff[%d] = *d\n", i, buff[i]);

79 }

80 return(NULL);

81 }

Помещение очередного элемента в массив

50-58 Для блокирования критической области в потоке-производителе теперь используется исключение put.mutex. 

Уведомление потребителя

59-64 Мы увеличиваем счетчик nready.nready, в котором хранится количество элементов, готовых для обработки потребителем. Перед его увеличением мы проверяем, не было ли значение счетчика нулевым, и если да, то вызывается функция pthread_cond_signal, позволяющая возобновить выполнение всех потоков (в данном случае потребителя), ожидающих установки ненулевого значения этой переменной. Теперь мы видим, как взаимодействуют взаимное исключение и связанная с ним условная переменная. Счетчик используется совместно потребителем и производителями, поэтому доступ к нему осуществляется с блокировкой соответствующего взаимного исключения (nready.mutex). Условная переменная используется для ожидания и передачи сигнала.

Потребитель ждет, пока значение nready.nready не станет отличным от нуля

72-76 Потребитель просто ждет, пока значение счетчика nready. nready не станет отличным от нуля. Поскольку этот счетчик используется совместно с производителями, его значение можно проверять только при блокировке соответствующего взаимного исключения. Если при проверке значение оказывается нулевым, мы вызываем pthread_cond_wait для приостановки процесса. При этом выполняются два атомарных действия:

1. Разблокируется nready.mutex.

2. Выполнение потока приостанавливается, пока какой-нибудь другой поток не вызовет pthread_cond_signal для этой условной переменной.

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

Код, передающий сигнал условной переменной, выглядит следующим образом:

struct {

 pthread_mutex_t mutex;

 pthread_cond_t cond;

 переменные, для которых устанавливается условие

} var = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, … };

Pthread_mutex_lock(&var.mutex);

установка истинного значения условия

Pthread_cond_signal(&var.cond);

Pthread_mutex_unlock(&var.mutex);

В нашем примере переменная, для которой устанавливалось условие, представляла собой целочисленный счетчик, а установка условия означала просто увеличение счетчика. Мы оптимизировали программу, посылая сигнал только при изменении значения счетчика с 0 на 1.

Код, проверяющий условие и приостанавливающий процесс, если оно не выполняется, обычно выглядит следующим образом:

Pthread_mutex_lock(&var.mutex);

while (условие ложно)

 Pthread_cond_wait(&var.cond, &var.mutex);

изменение условия

Pthread_mutex_unlock(&var.mutex);

Исключение конфликтов блокировок

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

int dosignal;

Pthread_mutex_lock(nready.mutex);

dosignal = (nready.nready == 0);

nready.nready++;

Pthread_mutex_unlock(&nready.mutex);

if (dosignal)

 Pthread_cond_signal(&nready.cond);

Здесь мы отправляем сигнал условной переменной только после разблокирования взаимного исключения. Это разрешено стандартом Posix: поток, вызывающий pthread_cond_signal, не обязательно должен в этот момент блокировать связанное с переменной взаимное исключение. Однако Posix говорит, что если требуется предсказуемое поведение при одновременном выполнении потоков, это взаимное исключение должно быть заблокировано процессом, вызывающим pthread_cond_signal.

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

Атаман. Гексалогия

Корчевский Юрий Григорьевич
Фантастика:
попаданцы
альтернативная история
историческое фэнтези
8.17
рейтинг книги
Атаман. Гексалогия

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

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

Тринадцатый IV

NikL
4. Видящий смерть
Фантастика:
боевая фантастика
попаданцы
5.00
рейтинг книги
Тринадцатый IV

Путь Князя. Возрождение. Часть I

Рокотов Алексей
6. Путь князя
Фантастика:
рпг
попаданцы
5.00
рейтинг книги
Путь Князя. Возрождение. Часть I

Базис

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

Страж Кодекса. Книга III

Романов Илья Николаевич
3. КО: Страж Кодекса
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Страж Кодекса. Книга III

Паладин из прошлого тысячелетия

Еслер Андрей
1. Соприкосновение миров
Фантастика:
боевая фантастика
попаданцы
6.40
рейтинг книги
Паладин из прошлого тысячелетия

Локки 2. Потомок бога

Решетов Евгений Валерьевич
2. Локки
Фантастика:
городское фэнтези
аниме
попаданцы
5.00
рейтинг книги
Локки 2. Потомок бога

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

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

Хозяин зеркал

Зонис Юлия
Фантастика:
социально-философская фантастика
7.57
рейтинг книги
Хозяин зеркал

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

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

Страж Кодекса

Романов Илья Николаевич
1. КО: Страж Кодекса
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Страж Кодекса

Хозяин Стужи 7

Петров Максим Николаевич
7. Злой Лед
Фантастика:
аниме
фэнтези
попаданцы
5.00
рейтинг книги
Хозяин Стужи 7

Геном хищника. Книга шестая

Гарцевич Евгений Александрович
6. Я - Легенда!
Старинная литература:
прочая старинная литература
5.00
рейтинг книги
Геном хищника. Книга шестая