6.3.1 Создание потока и выход из него

Предыдущая  Содержание  Следующая V*D*V

Новый поток выполнения создается вызовом функции pthread_create. Прототип функции:

 

int pthread_create (pthread_t * thread_id,

                    pthread_attr_t *thread_attributes,

                    void * (*start_routine)(void *),

                    void * arg);

 

Функция возвращает ноль в случае успеха, а идентификатор созданного потока хранится в первом аргументе, thread_id. Новый поток начинает свое выполнение с функции start_routine. arg является аргументом start_routine. thread_attributes представляет собой различные атрибуты потока, такие как политика планирования, приоритет, размер стека, и тому подобное. В случае неудачи функция возвращает ненулевое значение.

Давайте обратимся к нашему MP3-плееру в player.c. При запуске плеера для инициализации всех подсистем вызывается функция system_init. Функция system_init выполняется в контексте основного потока.

 

int system_init(){

  pthread_t audio_tid;

  int sample = 1;

  void * audio_init_status;

  /* Инициализируем звуковую подсистему в отдельном потоке */

  if (pthread_create(&audio_tid, NULL, audio_init,

                        (void *)sample) != 0){

    printf("Audio thread creation failed.\n");

    return FAIL;

  }

  /*

   * Инициализируем остальное приложение, структуры данных и т.д.

   */

 

  ....

  ....

}

 

Чтобы осуществить инициализацию звуковой подсистемы в новом потоке, system_init вызывает pthread_create. В случае успеха идентификатор потока созданного потока сохраняется в audio_tid. Новый поток выполняет функцию audio_init. audio_init принимает целочисленный аргумент sample. Вторым аргументом pthread_create является NULL, поток audio_tid начинает работать со стандартным набором атрибутов. (Например, политика планирования и приоритет потока наследуются от вызывающего.)

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

 

void* audio_init(void *sample){

  int init_status = SUCCESS;

  printf("Audio init thread created with ID %d\n",

                                  pthread_self());

  /*

   * Инициализируем подсистему MP3 декодера.

   * При неудаче устанавливаем init_status = FAIL.

   */

  /*

   * Инициализируем подсистему вывода звука.

   * При неудаче устанавливаем init_status = FAIL.

   */

 

  if ((int)sample){

 

  /*

   * Проигрываем звук в течение 2-х секунд.

   * При неудаче при воспроизведении

   * устанавливаем init_status = FAIL.

   */

 }

  printf("Audio subsystem initialized\n");

 

  pthread_exit((void *)init_status);

}

 

Возникают два вопроса:

 

Как поток audio_init может отправить своё выходное состояние в основной поток?

Может ли функция system_init подождать окончания потока audio_init перед выходом? Как можно передать выходное  состояние потока audio_init?

 

Поток устанавливает своё выходное состояние используя функцию pthread_exit. Эта функция также завершает выполнение вызывающего потока.

 

void pthread_exit(void *return_val);

 

audio_init вызывает pthread_exit, чтобы прекратить его выполнение, а также установить его состояние завершения. pthread_exit аналогичен системному вызову exit. С точки зрения разработчика приложения есть только одна разница: exit завершает весь процесс, а pthread_exit прекращает только вызывающий поток.

Поток может получить выходное состояние другого потока вызовом функции pthread_join.

 

int pthread_join(pthread_t tid, void **thread_return_val);

 

pthread_join приостанавливает выполнение вызывающего потока до завершения потока tid. Когда pthread_join возвращается, выходное состояние потока tid сохраняется в аргументе thread_return_val. pthread_join аналогичен системному вызову wait4. wait4 приостанавливает выполнение родительского процесса до тех пор, пока потомок, указанный в его аргументе, не завершится. Аналогично, pthread_join также приостанавливает выполнение вызывающего потока, пока поток, указанный в его аргументе, не завершится. Как вы можете видеть, system_init вызывает pthread_join, чтобы дождаться перед выходом завершения потока audio_init. Она также печатает сообщение об ошибке, если audio_init заканчивается неудачей.

 

int system_init(){

    ...

  void * audio_init_status;

    ...

    ...

  /* Ожидаем завершения потока audio_init */

  pthread_join(audio_tid, &audio_init_status);

 

  /* Если инициализация звука не удалась, возвращаем ошибку */

  if ((int)audio_init_status == FAIL){

    printf("Audio init failed.\n");

    return FAIL;

  }

 

  return SUCCESS;

}

 

Обратите внимание, что поток, создаваемый с помощью pthread_create со стандартным набором атрибутов (вторым аргументом pthread_create является NULL), является потоком, допускающим объединение. Ресурсы, выделяемые на объединяемые потоки, не освобождаются, пока какой-нибудь другой поток вызывает pthread_join для такого потока. Он становится зомби.

 

Предыдущая  Содержание  Следующая