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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 224 225 226 227 228 229 230 231 232 ... 324

#define NUM_THREADS 6

void *thread_function(void *arg);

int main() {

 int res;

 pthread_t a_thread[NUM_THREADS];

 void *thread_result;

 int lots_of_threads;

 for (lots_of_threads = 0; lots_of_threads < NUM_THREADS; lots_of_threads++) {

<i>  res = pthread_create(&amp;(a_thread[lots_of_thread]), NULL,</i>

<i>   thread_function, (void*)lots_оf_threads);</i>

<i>  if (res != 0) {</i>

<i>   perror(&quot;Thread creation failed&quot;);</i>

<i>   exit(EXIT_FAILURE);</i>

<i>  }</i>

 }

 printf(&quot;Waiting for threads to finish...n&quot;);

 for (lots_of_threads = NUM_THREADS - 1; lots_of_threads &gt;= 0;

  lots of threads--) {

  res = pthread_join(a_thread[lots_of_threads], &amp;thread_result);

  if (res == 0) {

   printf(&quot;Picked up a threadn&quot;);

  } else {

   perror(&quot;pthread_join failed&quot;);

  }

 }

 printf(&quot;All donen&quot;);

 exit(EXIT_SUCCESS);

}

<i>void* thread_function(void* arg) {</i>

<i> int my_number = (int)arg;</i>

 int rand_num;

 printf(&quot;thread_function is running. Argument was %dn&quot;, my_number);

 rand_num = 1+(int)(9.0*rand()/(RAND_MAX+1.0));

 sleep(rand_num);

 printf(&quot;Bye from %dn&quot;, my_number);

 pthread_exit(NULL);

}

Резюме

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

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

Глава 13

Связь между процессами: каналы

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

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

В данной главе мы обсудим следующие темы:

□ определение канала;

□ каналы процессов;

□ вызовы каналов;

□ родительские и дочерние процессы;

□ именованные каналы — FIFO;

□ замечания, касающиеся клиент-серверных приложений.

Что такое канал?

Мы применяем термин "канал" для обозначения соединения потока данных одного процесса с другим. Обычно вы присоединяете или связываете каналом вывод одного процесса с вводом другого.

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

cmd1 | cmd2

Командная оболочка организует стандартный ввод и вывод двух команд так, что:

□ стандартный ввод cmd1 поступает с клавиатуры терминала;

□ стандартный вывод cmd1 поставляется cmd2 как ее стандартный ввод;

□ стандартный вывод cmd2 подсоединен к экрану терминала.

На самом деле командная оболочка заново соединила потоки стандартных ввода и вывода так, что потоки данных проходят с клавиатурного ввода через две команды и выводятся на экран. На рис. 13.1 приведено визуальное представление этого процесса.

Рис. 13.1 

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

Каналы процессов

Возможно, простейший способ передачи данных между программами — применение функций popen и pclose. У них следующие прототипы:

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

<b>FILE *popen(const char *command, const char *open_mode);</b>

<b>int pclose(FILE *stream_to_close);</b>

popen

Функция popen позволяет программе запустить другую программу как новый процесс и либо передать ей данные, либо получить их из нее. Строка command — это имя программы для выполнения вместе с любыми параметрами, параметр open_mode должен быть &quot;r&quot; или &quot;w&quot;.

Если open_mode — &quot;r&quot;, вывод вызванной программы становится доступен вызывающей программе и может быть считан из возвращаемого функцией popen файлового потока FILE* с помощью обычных функций библиотеки stdio, предназначенных для чтения (например, fread). Но если open_mode — &quot;w&quot;, программа может отправить данные вызванной команде с помощью вызова функции fwrite. Далее вызванная программа сможет читать данные из своего стандартного ввода. Обычно вызванная программа не знает, что она считывает данные из другого процесса; она просто читает свой поток стандартного ввода и воздействует на него.

1 ... 224 225 226 227 228 229 230 231 232 ... 324
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Основы программирования в Linux - Мэтью Нейл.

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