Вход/Регистрация
Основы программирования в Linux
вернуться

Мэтью Нейл

Шрифт:

$ ./thread3a

Input some text. Enter 'end' to finish

Excession

You input 9 characters

FAST

You input 7 characters

You input 7 characters

You input 7 characters

end

Waiting for thread to finish...

Thread joined

Проблема этой программы заключается в том, что она рассчитывала на то, что ввод текста из программы продлится так долго, что у другого потока хватит времени для подсчета символов до того, как поток

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

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

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

Синхронизация с помощью мьютексов

Другой способ синхронизации доступа в многопоточных программах — применение мьютексов (сокращение от mutual exclusions — взаимные исключения) или исключающих семафоров, которые разрешают программистам "запирать" объект так, что только один поток может обратиться к нему.

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

#include <рthread.h>

int pthread_mutex_init(pthread_mutex_t* mutex,

 const pthread_mutexattr_t *mutexattr);

int pthread_mutex_lock(pthread_mutex_t* mutex);

int pthread_mutex_unlock(pthread mutex_t* mutex);

int pthread_mutex_destroy(pthread_mutex_t *mutex);

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

errno
не задается, вам придется использовать код возврата.

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

pthread_mutex_t
. Дополнительный параметр атрибутов в функции
pthread_mutex_init
позволяет задать атрибуты мьютекса, управляющие его поведением. По умолчанию тип атрибута — "fast". У него есть небольшой недостаток: если ваша программа попытается вызвать функцию
pthread_mutex_lock
для мьютекса, который уже заблокирован, программа блокируется. Поскольку поток, удерживающий блокировку, в данный момент заблокирован, мьютекс никогда не будет открыт, и программа попадает в тупиковую ситуацию. Есть возможность изменить атрибуты мьютекса так, чтобы он либо проверял наличие такой ситуации и возвращал ошибку, либо действовал рекурсивно и разрешал множественные блокировки тем же самым потоком, если будет такое же количество разблокировок в дальнейшем.

Установка атрибутов мьютекса в этой книге не рассматривается, поэтому мы будем передавать

NULL
в указателе на атрибуты, и использовать поведение по умолчанию. Дополнительную информацию об изменении атрибутов можно найти в интерактивном справочном руководстве к функции
pthread_mutex_init
.

Выполните упражнение 12.4. 

Упражнение 12.4. Мьютекс потока

Далее приводится еще одна модификация исходной программы thread1.с, но значительно измененная. На этот раз вы уделите особое внимание доступу к вашим важным переменным и примените мьютекс для того, чтобы быть уверенными в том, что они доступны в любой момент времени только одному потоку. Для легкости чтения текста примера мы пропустили некоторые проверки ошибок при возвратах из мьютекса, заблокированного и открытого. В рабочем программном коде вы обязательно должны проверять эти возвращаемые значения. Далее приведен текст новой программы thread4.c.

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <string.h>

#include <pthread.h>

#include <semaphore.h>

void *thread_function(void *arg);

pthread_mutex_t work_mutex; /* защищает work_area и time_to_exit */

#define WORK_SIZE 1024

char work_area[WORK_SIZE];

int time_to_exit = 0;

int main {

 int res;

 pthread_t a_thread;

 void *thread_result;

 res = pthread_mutex_init(&work_mutex, NULL);

 if (res != 0) {

perror("Mutex initialization failed");

exit(EXIT_FAILURE);

 }

  • Читать дальше
  • 1
  • ...
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • ...

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

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

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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