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

ЖАНРЫ

Основы программирования в Linux
Шрифт:

 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...");

 } else {

fgets(work_area, WORK_SIZE, stdin);

 }

 sem_post(&bin_sem);

}

Теперь, если вы введете

FAST
, программа вызовет
sem_post
, чтобы запустить счетчик символов, но немедленно обновит
work_area
чем-то другим.

$ cc -D_REENTRANT thread3a.с -о thread3a -lpthread

$ ./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...
, формируемое автоматически), у второго потока не было времени для выполнения. Но семафор наращивался несколько раз, поэтому считающий поток продолжал считать слова и уменьшал значение семафора до тех пор, пока оно снова не стало нулевым.

Поделиться с друзьями: