6.3.1 Создание потока и выход из него |
Предыдущая Содержание Следующая |
Новый поток выполнения создается вызовом функции 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 для такого потока. Он становится зомби.
|
Предыдущая Содержание Следующая |