Читать интересную книгу Основы программирования в Linux - Мэтью Нейл

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 215 216 217 218 219 220 221 222 223 ... 324

Следующая пара функций управляет значением семафора и объявляется следующим образом.

<b>#include &lt;semaphore.h&gt;</b>

<b>int sem_wait(sem_t* sem);</b>

<b>int sem_post(sem_t* sem);</b>

Обе они принимают указатель на объект-семафор, инициализированный вызовом sem_init.

Функция sem_post атомарно увеличивает значение семафора на 1. Атомарно в данном случае означает, что если два потока одновременно пытаются увеличить значение единственного семафора на 1, они не мешают друг другу, как в случае двух программ, которые читают, увеличивают и записывают значение в файл в одно и то же время. Если обе программы пытаются увеличить значение на 1, семафор всегда будет корректно увеличивать значение на 2.

Функция sem_wait атомарно уменьшает значение семафора на единицу, но всегда ждет до тех пор, пока сначала счетчик семафора не получит ненулевое значение. Таким образом, если вы вызываете sem_wait для семафора со значением 2, поток продолжит выполнение, а семафор будет уменьшен до 1. Если sem_wait вызывается для семафора со значением 0, функция будет ждать до тех пор, пока какой-нибудь другой поток не увеличит значение, и оно станет ненулевым. Если оба потока ждут в функции sem_wait, чтобы один и тот же семафор стал ненулевым, и он увеличивается когда-нибудь третьим потоком, только один из двух ждущих потоков получит возможность уменьшить семафор и продолжиться; другой поток так и останется ждущим. Эта атомарная способность "проверить и установить" в одной функции и делает семафор столь ценным.

Примечание

Есть и другая функция семафора sem_trywait — это неблокирующий партнер sem_wait. Мы не будем ее обсуждать в книге в дальнейшем, дополнительную информацию см. в интерактивном справочном руководстве.

Последняя функция семафоров — sem_destroy. Она очищает семафор, когда вы закончили работу с ним, и объявляется следующим образом:

<b>#include &lt;semaphore.h&gt;</b>

<b>int sem_destroy(gem_t* sem);</b>

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

Как и большинство других, функций, все перечисленные функции возвращают 0 в случае успешного завершения.

А теперь выполните упражнение 12.3.

Упражнение 12.3. Семафор потока

Текст этой программы thread3.c также основан на тексте программы thread1.c. Поскольку изменения значительны, мы приводим новый вариант полностью.

#include &lt;stdio.h&gt;

#include &lt;unistd.h&gt;

#include &lt;stdlib.h&gt;

#include &lt;string.h&gt;

#include &lt;pthread.h&gt;

#include &lt;semaphore.h&gt;

void *thread_function(void *arg);

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(&amp;bin_sem, 0, 0);

 if (res != 0) {

  perror(&quot;Semaphore initialization failed&quot;);

  exit(EXIT_FAILURE);

 }

 res = pthread_create(&amp;a_thread, NULL, thread_function, NULL);

 if (res != 0) {

  perror(&quot;Thread creation failed&quot;);

  exit(EXIT_FAILURE);

 }

 printf(&quot;Input some text. Enter 'end' to finishn&quot;);

 while (strncmp(&quot;end&quot;, work_area, 3) != 0) {

  fgets(work_area, WORK_SIZE, stdin);

  sem_post(&amp;bin_sem);

 }

 printf(&quot;nWaiting for thread to finish...n&quot;);

 res = pthread_join(a_thread, &amp;thread_result);

 if (res != 0) {

  perror(&quot;Thread join failed&quot;);

  exit(EXIT_FAILURE);

 }

 printf(&quot;Thread joinedn&quot;);

 sem_destroy(&amp;bin_sem);

 exit(EXIT_SUCCESS);

}

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

 while(strncmp(&quot;end&quot;, work area, 3) != 0) {

  printf(&quot;You input %d charactersn&quot;, strlen(work_area)-1);

  sem_wait(&amp;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(&amp;bin_sem, 0, 0);

 if (res != 0) {

  perror(&quot;Semaphore initialization failed&quot;);

1 ... 215 216 217 218 219 220 221 222 223 ... 324
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Основы программирования в Linux - Мэтью Нейл.

Оставить комментарий