pthread_key_create деструктор не вызывается

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

static pthread_key_t key;
static pthread_once_t tls_init_flag = PTHREAD_ONCE_INIT;

void destructor(void *t) {
// thread local data structure clean up code here, which is not getting called
}

void create_key() {
pthread_key_create(&key, destructor);
}

// This will be called from every thread
void set_thread_specific() {

ts = new ts_stack; // Thread local data structure

pthread_once(&tls_init_flag, create_key);
pthread_setspecific(key, ts);
}

Есть идеи, что может помешать этому деструктору вызвать? Я также использую atexit () в данный момент, чтобы выполнить некоторую очистку в основном потоке. Есть ли шанс, что это мешает вызову функции деструктора? Я попытался удалить это также. Все еще не работал все же. Также мне не ясно, должен ли я обрабатывать основной поток как отдельный случай с atexit. (Кстати, использовать atexit обязательно, так как мне нужно выполнить некоторую очистку приложения при выходе из приложения)

7

Решение

Это по замыслу.

Основной поток завершается (возвращением или вызовом exit()), и это не использует pthread_exit(), Документы POSIX pthread_exit вызов деструкторов, специфичных для потока.

Вы могли бы добавить pthread_exit() в конце main, Кроме того, вы можете использовать atexit сделать ваше уничтожение. В этом случае было бы чисто установить значение для потока в NULL так что в случае pthread_exit был вызван, разрушение не произошло бы дважды для этого ключа.

ОБНОВИТЬ На самом деле, я решил свои непосредственные проблемы, просто добавив это в мою глобальную функцию настройки модульного теста:

::atexit([] { ::pthread_exit(0); });

Итак, в контексте моего глобального класса фикстуры MyConfig:

struct MyConfig {
MyConfig()   {
GOOGLE_PROTOBUF_VERIFY_VERSION;
::atexit([] { ::pthread_exit(0); });
}
~MyConfig()  { google::protobuf::ShutdownProtobufLibrary(); }
};

Некоторые из использованных ссылок:


PS. Конечно с ++ 11 введены <thread> так что у вас есть лучшие и более портативные примитивы для работы.

2

Другие решения

Это уже в ответе Сехе, просто представить ключевые моменты в сжатой форме:

  • pthread_key_create() вызовы деструктора запускаются вызовом pthread_exit(),
  • Если процедура запуска потока возвращается, поведение такое pthread_exit() был вызван (т.е. вызовы деструктора инициированы).
  • тем не мение, если main() возвращается, поведение как будто exit() был вызван — вызовы деструкторов не запускаются.

Это объясняется в http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html. См. Также C ++ 17 6.6.1p5 или C11 5.1.2.2.3p1.

1

Я написал быстрый тест, и единственное, что я изменил, было перемещение create_key Ваш звонок за пределами set_thread_specific,

То есть я назвал это в основном потоке.

Затем я увидел, как вызывается мой destroy при выходе из подпрограммы потока.

0

Я звоню деструктор () вручную в конце главный():

void * ThreadData = NULL;

if ((ThreadData = pthread_getspecific(key)) != NULL)
destructor(ThreadData);

Конечно ключ должны быть должным образом инициализированы ранее в главный() код.
PS. призвание Pthread_exit () в конце главный() кажется зависает целое приложение …

0

Ваша первоначальная мысль об обработке основного потока как отдельного случая с atexit работала лучше всего для меня.

Имейте в виду, что pthread_exit (0) перезаписывает значение выхода процесса. Например, следующая программа выйдет с нулевым статусом, хотя main () вернется с номером три:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

class ts_stack {
public:
ts_stack () {
printf ("init\n");
}
~ts_stack () {
printf ("done\n");
}
};

static void cleanup (void);

static pthread_key_t key;
static pthread_once_t tls_init_flag = PTHREAD_ONCE_INIT;

void destructor(void *t) {
// thread local data structure clean up code here, which is not getting called
delete (ts_stack*) t;
}

void create_key() {
pthread_key_create(&key, destructor);
atexit(cleanup);
}

// This will be called from every thread
void set_thread_specific() {
ts_stack *ts = new ts_stack (); // Thread local data structure

pthread_once(&tls_init_flag, create_key);
pthread_setspecific(key, ts);
}

static void cleanup (void) {
pthread_exit(0); // <-- Calls destructor but sets exit status to zero as a side effect!
}

int main (int argc, char *argv[]) {
set_thread_specific();
return 3; // Attempt to exit with status of 3
}
0
По вопросам рекламы [email protected]