printf("\nWaiting for thread to finish...\n");

 res = pthread_join(a_thread, &thread_result);

 if (res != 0) {

  perror("Thread join failed");

  exit(EXIT_FAILURE);

 }

 printf("Thread joined\n");

 sem_destroy(&bin_sem);

 exit(EXIT_SUCCESS);

}

void *thread function(void *arg) { sem_wait(&bin_sem);

 while(strncmp("end", work area, 3) != 0) {

  printf("You input %d characters\n", strlen(work_area)-1);

  sem_wait(&bin_sem);

 }

 pthread_exit(NULL);

}

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

sem_t bin_sem;

#define WORK_SIZE 1024

char work_area[WORK_SIZE];

int main() {

 int res;

 pthread_t a_thread;

 void *thread_result;

 res = sem_init(&bin_sem, 0, 0);

 if (res != 0) {

  perror("Semaphore initialization failed");

  exit(EXIT_FAILURE);

 }

Обратите внимание на то, что начальное значение семафора равно 0.

В функции main, после того как вы запустили новый поток, вы читаете некоторый текст с клавиатуры, загружаете вашу рабочую область и затем наращиваете счетчик семафора с помощью sem_post:

 printf("Input some text. Enter 'end' to finish\n");

 while(strncmp("end", work_area, 3) != 0) {

  fgets(work_area, WORK_SIZE, stdin);

  sem_post(&bin_sem);

 }

В новом потоке вы ждете семафор и затем подсчитываете символы ввода:

 sem_wait(&bin_sem);

 while(strncmp("end", work_area, 3) != 0) {

  printf("You input %d characters\n", strlen(work_area)-1);

  sem_wait(&bin_sem);

 }

Пока семафор установлен, вы ждете ввода с клавиатуры. Когда вы получите некоторый ввод, то освобождаете семафор, разрешив второму потоку сосчитать символы перед тем, как первый поток начнет снова считывать ввод с клавиатуры.

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

Дайте программе отработать:

$ cc -D_REENTRANT thread3.с -о threads -lpthread

$ ./thread3

Input some text. Enter 'end', to finish

The Wasp Factory

You input 16 characters

Iain Banks

You input 10 characters

end

Waiting for thread to finish...

Thread joined

В программах с потоками временные ошибки всегда трудно найти, но программа кажется приспособленной и к быстрому вводу текста, и более неспешным паузам.

Как это работает

Когда вы инициализируете семафор, то задаете ему начальное значение, равное 0. Следовательно, когда запускается функция потока, вызов sem_wait приостанавливает выполнение и ждет, когда семафор станет ненулевым.

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

Неочевидные недочеты в разработке, которые заканчиваются в результате неявными ошибками, легко пропустить. Давайте слегка изменим программу на thread3a.c, так чтобы вводимый с клавиатуры текст временами заменялся автоматически формируемым текстом. Замените цикл чтения в main следующим:

printf("Input some text. Enter 'end' to finish\n");

while (strncmp("end", work_area, 3) != 0) {

 if (strncmp(work_area, "FAST", 4) == 0) {

  sem_post(&bin_sem);

  strcpy(work_area, "Wheeee...");

Перейти на страницу:

Похожие книги