4.3.2. Очистка потоковых данных в C++

4.3.2. Очистка потоковых данных в C++

Программисты, работающие на C++, привыкли к тому, что очистку за них делают деструкторы объектов. Когда объект выходит за пределы своей области видимости, либо по достижении конца блока, либо вследствие возникновения исключительной ситуации, среда выполнения C++ гарантирует вызов деструкторов для тех автоматических переменных, у которых они есть. Это удобный механизм очистки, работающий независимо от того, как осуществляется выход из конкретного программного блока.

Тем не менее, если поток вызывает функцию pthread_exit(), среда выполнения C++ не может гарантировать вызов деструкторов для всех автоматических переменных, находящихся в стеке потока. Чтобы этого добиться, нужно вызвать функцию pthread_exit() в рамках конструкции try/catch, охватывающей все тело потоковой функции. При этом перехватывается специальное исключение ThreadExitException.

Программа, приведенная в листинге 4.9, иллюстрирует данную методику. Потоковая функция сообщает о своем намерении завершить поток, генерируя исключение ThreadExitException, а не вызывая функцию pthread_exit() явно. Поскольку исключение перехватывается на самом верхнем уровне потоковой функции, все локальные переменные, находящиеся в стеке потока, будут удалены правильно.

Листинг 4.9. (cxx-exit.cpp) Безопасное завершение потока в C++

#include <pthread.h>

class ThreadExitException {

public:

 /* Конструктор, принимающий аргумент RETURN_VALUE, в котором

    содержится возвращаемое потоком значение. */

 ThreadExitException(void* return_value) :

  thread_return_value_(return_value) {

 }

 /* Реальное завершение потока. В программу возвращается

    значение, переданное конструктору. */

 void* DoThreadExit() {

  pthread_exit(thread_return_value_);

 }

private:

 /* Значение, возвращаемое в программу при завершении потока. */

 void* thread_return_value_;

};

void do_some_work() {

 while (1) {

  /* Здесь выполняются основные действия... */

  if (should_exit_thread_immediately())

   throw ThreadExitException(/* поток возвращает */NULL);

 }

}

void* thread_function(void*) {

 try {

  do_some_work();

 } catch (ThreadExitException ex) {

  /* Возникла необходимость завершить поток. */

  ex.DoThreadExit();

 }

 return NULL;

}