Le thread principal est-il autorisé à générer un thread POSIX avant qu’il entre main ()?

J’ai cet object qui contient un fil. Je veux que le sort de l’object et le sort du fil soient un dans le même. Ainsi, le constructeur crée un thread (avec pthread_create ) et le destructeur effectue des actions pour que le thread retourne dans un délai raisonnable, puis rejoint le thread. Cela fonctionne bien tant que je n’instancie pas l’un de ces objects avec une durée de stockage statique. Si j’instancie l’un de ces objects au niveau global, de l’espace de noms ou de la classe statique, le programme est bien compilé (gcc 4.8.1) mais segfa immédiatement après l’exécution. Avec les instructions print, j’ai déterminé que le thread principal n’entre même pas main () avant le segfault. Des idées?

Mise à jour: Ajoute également une instruction print à la première ligne du constructeur (donc avant l’appel de pthread_create ), et même si elle est imprimée avant le segfault MAIS le constructeur utilise une liste d’initialisation afin qu’il soit possible que quelque chose l’ait provoquée?

Voici le constructeur:

 worker::worker(size_t buffer_size): m_head(nullptr),m_tail(nullptr), m_buffer_A(operator new(buffer_size)), m_buffer_B(operator new(buffer_size)), m_next(m_buffer_A), m_buffer_size(buffer_size), m_pause_gate(true), m_worker_thread([this]()->void{ thread_func(); }), m_running(true) { print("this wont get printed b4 segfault"); scoped_lock lock(worker_lock); m_worker_thread.start(); all_workers.push_back(this); } 

Et destructeur:

 worker::~worker() { { scoped_lock lock(worker_lock); auto w=all_workers.begin(); while(w!=all_workers.end()) { if(*w==this) { break; } ++w; } all_workers.erase(w); } { scoped_lock lock(m_lock); m_running=false; } m_sem.release(); m_pause_gate.open(); m_worker_thread.join(); operator delete(m_buffer_A); operator delete(m_buffer_B); } 

Mise à jour 2:

Ok je l’ai compris. Ma fonction print est atomique et protège également cout avec un mutex de scope de noms externe défini ailleurs. J’ai changé pour simplement cout et imprimé au début du ctor. Apparemment, aucun de ces mutex de durée de stockage statique n’est en cours d’initialisation avant que les utilisateurs ne tentent d’y accéder. Alors oui, c’est probablement la réponse de Casey.

Je ne vais tout simplement pas m’embêter avec des objects complexes et la durée de stockage statique. Ce n’est pas grave quand même.

L’initialisation de variables non locales est décrite dans C ++ 11 § 3.6.2, il y a une tonne de choses effrayantes au paragraphe 2 qui ont à voir avec les threads:

Si un programme démarre un fil (30.3), l’initialisation ultérieure d’une variable n’est pas séquencée par rapport à l’initialisation d’une variable définie dans une unité de traduction différente. Sinon, l’initialisation d’une variable est séquencée de manière indéterminée par rapport à l’initialisation d’une variable définie dans une unité de traduction différente. Si un programme démarre une unité d’exécution, l’initialisation non ordonnée ultérieure d’une variable n’est pas séquencée par rapport à toute autre initialisation dynamic.

J’interprète “l’initialisation ultérieure non ordonnée d’une variable par rapport à chaque initialisation dynamic” comme signifiant que le thread généré ne peut accéder à aucune variable avec une initialisation dynamic qui n’a pas été initialisée avant que le thread ne soit généré sans provoquer une course de données. Si ce fil ne se synchronise pas avec main , vous dansez dans un champ de mines avec vos mains sur vos yeux.

Je vous suggère fortement de lire et de comprendre l’intégralité de la version 3.6; même sans fil, c’est un énorme PITA à faire beaucoup avant les départs main .

Ce qui se passe avant d’entrer dans main sera spécifique à la plate-forme, mais voici un lien sur la façon dont main () s’exécute sous Linux

http://linuxgazette.net/84/hawk.html

Le snipet utile est

__libc_start_main initialise les éléments nécessaires, notamment la bibliothèque C (telle que malloc) et l’environnement de threads, et appelle notre principal.

Pour plus d’informations, consultez __libc_start_main

Je ne sais pas comment cela se comporte sous Windows, mais il semble que tout appel d’une bibliothèque C standard avant d’entrer dans main n’est pas une bonne idée.

Il y a peut-être plusieurs façons de le faire. Voir l’extrait ci-dessous où le constructeur de la classe A a appelé avant main car nous avons déclaré un object de classe A à scope globale: (J’ai développé l’exemple pour montrer comment un thread peut être créé avant l’exécution de main)

 #include  #include  #include  using namespace std; void *fun(void *x) { while (true) { cout << "Thread\n"; sleep(2); } } pthread_t t_id; class A { public: A() { cout << "Hello before main \n " ; pthread_create(&t_id, 0, fun, 0); sleep(6); } }; A a; int main() { cout << "I am main\n"; sleep(40); return 0; }