Новосибирский Государственный Университет
Опубликован: 28.04.2010 | Доступ: свободный | Студентов: 684 / 60 | Оценка: 4.62 / 4.24 | Длительность: 10:21:00
Лекция 3:

Создание и завершение нитей

< Лекция 2 || Лекция 3: 1234 || Лекция 4 >

3. Ожидание завершения нити

Для ожидания завершения нити и получения ее кода возврата используется библиотечная функция pthread_join(3C). Эта функция имеет два параметра, идентификатор нити типа pthread_t, и указатель на переменную типа void *, в которой размещается значение кода возврата. Если в качестве второго параметра передать нулевой указатель, код возврата игнорируется.

Если требуемая нить еще не завершилась, то нить, сделавшая вызов pthread_join(3С), блокируется. Если такой нити (уже) не существует, pthread_join(3C) возвращает ошибку ESRCH.

Когда нить завершается, то связанные с ней ресурсы существуют до того момента, пока какаято другая нить не вызовет pthread_join(3C). Однако к тому моменту, когда pthread_join завершается, все ресурсы, занятые нитью (стек, thread local data, дескриптор нити) уничтожаются.

В отличие от процессов Unix, где системный вызов wait(2) может использовать только родитель по отношению к потомкам, любая нить может ждать завершения любой другой нити того же процесса. Если несколько нитей ждут завершения одной и той же нити, которая еще не завершилась, все эти нити блокируются. Однако при завершении нити одна из ожидавших нитей получает код возврата, а остальные ошибку ESRCH.

Если нить пытается ожидать сама себя, она получает ошибку EDEADLK.

Еще одна важная функция, связанная с ожиданием завершения нити – это функция pthread_detach(3C). Эта функция указывает, что все ресурсы, связанные с нитью, необходимо уничтожать сразу после завершения этой нити. При этом уничтожается и код возврата такой нити – при попытке сделать pthread_join(3C) на нить, над которой перед этим сделали pthread_detach(3C), возвращается код ошибки EINVAL.

В руководстве по pthread_detach(3C) в системе Solaris 10 сказано, что главное применение pthread_detach(3C) – это ситуация, когда родитель, ожидавший завершения дочерней нити, получает pthread_cancel(3C). В действительности, существуют и другие применения "отсоединенных" нитей.

Не обязательно делать pthread_detach(3C) на уже запущенную нить; в атрибутах нити ( pthread_attr_t ) можно указать, что нить следует запускать в уже "отсоединенном" состоянии.

Это рассматривается в следующей лекции.

Разумеется, нить, над которой сделали pthread_detach(3C), не должна выделять память под возвращаемое значение при помощи malloc(3C) – ведь никто не сможет освободить эту память и это приведет к утечке памяти.

Рекомендованного стандартом способа проверить собственную "отсоединенность" нет. Из предыдущего описания можно предположить, что для проверки "отсоединенности" можно было бы использовать код возврата pthread_join(3C) для собственного идентификатора нитей – для "отсоединенных" нитей это должен быть EINVAL, а для "неотсоединенных" – EDEADLK.

Для Solaris 10 и Linux 2.6 это действительно так (во всяком случае для Debian Sarge), однако в Linux 2.4 ptread_join(pthread_self(), NULL) всегда возвращает EDEADLK. Как ведет себя pthread_join на вашей системе, можно проверить при помощи программы примера 3.3.

Кроме нестандартности, данный способ не гарантирует, что вас не "отсоединят" уже после того, как вы осуществили проверку. То есть надежда на результат такой проверки может привести к ошибке соревнования (race condition). Поэтому применять такую проверку в реальных приложениях не следует.

#include <pthread.h> 
#include <errno.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <string.h> 

/* !!! NEVER USE THIS IN PRODUCTION ENVIRONMENT!!!! */ 
/* Behavior of this code implementation-dependent 
 * using this code "as is" will result in race condition */ 

void * thread_body(void *unused) { 
  pthread_t self; 
  int code; 
  self=pthread_self(); 
  
  code=pthread_join(self, NULL); 
  
  printf("Joining self before detach, error code=%d, message %s\n", 
         code, strerror(code));
  /* NEVER USE THIS CODE IN PRODUCTION ENVIRONMENT */ 
  pthread_detach(self); 
  code=pthread_join(self, NULL); 
  printf("Joining self after detach, error code=%d, message %s\n", 
         code, strerror(code)); 
  return NULL; 
} 

int main() { 
  pthread_t thread; 
  pthread_create(&thread, NULL, &thread_body, NULL); 
  pthread_exit(NULL); 
  return 0; 
}
3.3.

Поскольку стандартного способа проверить "отсоединенность" нити не существует, при разработке архитектуры приложения не следует полагаться на то, что способ этой проверки вообще доступен.

< Лекция 2 || Лекция 3: 1234 || Лекция 4 >