2
votes

Est-ce une bonne pratique d'appeler pthread_sigmask dans un thread créé par std :: thread?

1) Je suis nouveau sur std :: thread et j'aimerais savoir si c'est une bonne pratique d'appeler pthread_sigmask () pour bloquer certains signaux dans un particulier strong> thread créé par std :: thread .

Je ne veux pas que le nouveau thread reçoive des signaux tels que SIGTERM, SIGHUP, etc., car le processus principal a déjà installé des gestionnaires pour ceux-ci signaux.

Est-ce donc une bonne pratique d'appeler pthread_sigmask () pour bloquer certains signaux dans un thread créé par std :: thread ?

2) De plus, je crois que l'effet de pthread_sigmask (SIG_BLOCK, & mask, NULL) ne s'appliquera qu'au thread créé en utilisant

void rotate_log (std::string logfile, uint32_t max_files, bool compress)
{
    sigset_t mask;

    sigemptyset (&mask);
    sigaddset (&mask, SIGTERM);
    sigaddset (&mask, SIGHUP);
    pthread_sigmask(SIG_BLOCK, &mask, NULL);

    // Do other stuff.
}

void Log::log (std::string message)
    {
        // Lock using mutex
        std::lock_guard<std::mutex> lck(mtx);

        _outputFile << message << std::endl;
        _outputFile.flush();
        _sequence_number++;
        _curr_file_size = _outputFile.tellp();

        if (_curr_file_size >= max_size) {
            // Code to close the file stream, rename the file, and reopen
            ...


            // Create an independent thread to compress the file since
            // it takes some time to compress huge files.
            if (!_log_compression_on)
            {
                std::thread(&Log::rotate_log, this, _logfile, _max_files, _compress).detach();
            }
        }
    }

et en appelant rotate_log () comme fonction de démarrage.

Et l'effet de pthread_sigmask (SIG_BLOCK, & mask, NULL) ne s'appliquera pas au thread où std :: thread (& Log :: rotate_log, this, _logfile, _max_files, _compress) .detach () est appelé.

Ma compréhension est-elle correcte?

std::thread(&Log::rotate_log, this, _logfile, _max_files, _compress).detach();


2 commentaires

Cela supposerait à tout le moins que std :: thread est implémenté en termes de pthreads, ce qui peut ne pas être le cas.


J'ai déjà mentionné le but dans ma question comme "Je ne veux pas que le nouveau thread reçoive des signaux tels que SIGTERM, SIGHUP, etc., car le processus principal a déjà installé des gestionnaires pour ces signaux." Maintenant, dans ce contexte, je voudrais savoir si l'exemple ci-dessus sert cet objectif et si ce que je fais est une bonne pratique ou non.


3 Réponses :


1
votes

Si vous avez besoin de définir le masque de signal dans un programme multithread sur un système POSIX, alors pthread_sigmask est la fonction que vous devez utiliser. Il n'y a pas de fonctions pour interagir avec les masques de signaux dans la bibliothèque standard C ++.

De plus, je crois que l'effet de pthread_sigmask (SIG_BLOCK, & mask, NULL) ne s'appliquera qu'au thread créé en utilisant ...

pthread_sigmask s'applique au thread dans lequel l'appel a été exécuté, quelle que soit la façon dont le thread a été créé. Il ne s'applique à aucun autre thread préexistant. Dans le cas de votre exemple, la fonction rotate_log dans laquelle pthread_sigmask est appelé est exécutée dans le thread créé par std :: thread .


0 commentaires

3
votes

La manière correcte est de définir le masque de signal requis dans le parent avant de créer un thread, puis de le rétablir dans le parent. De cette façon, votre thread nouvellement créé a le masque de signal correct défini depuis son tout début. (Le masque de signal est hérité du thread parent).

Lorsque vous définissez le masque de signal après le thread a démarré, il y a une fenêtre de temps pendant laquelle le thread n'a pas le masque requis.


0 commentaires

5
votes

En théorie, il est possible qu'une implémentation de std :: thread crée un thread non POSIX même sur un système qui a des threads POSIX, et pthread_sigmask ne fonctionne pas pour de tels fils. ( Le commentaire de Maxim Egorushkin est correct, cependant, vous devriez vraiment bloquer les signaux dans le thread de création de thread et ne débloquer que ceux que vous voulez géré sur le nouveau thread, pour éviter les conditions de concurrence.)

Je ne peux pas parler d'autres implémentations, mais il est extrêmement improbable qu'une telle chose se produise pour l'implémentation GNU / Linux. Je ne peux pas non plus parler avec autorité de cette implémentation, bien sûr, mais il y a tout simplement trop de code C et C ++ qui suppose un mappage 1: 1 entre les threads de l'espace utilisateur (que ce soit C, C ++ ou POSIX) et les tâches du noyau (ces choses qui avoir des TID). Il y a dix ans, les gens soutenaient encore qu'une bibliothèque de threads n: m serait une possibilité (dont les premières implémentations 1: m des threads POSIX n'étaient qu'un cas particulier).

Mais aujourd'hui, les programmeurs appellent unshare (CLONE_FS) à partir d'un thread pour donner à ce thread un répertoire courant privé, séparé de tous les autres threads. Ils appellent setfscreatecon et s'attendent à ce que cela n'affecte que le thread appelant. Ils appellent même les appels système setresuid et setresgid directement parce qu'ils veulent éviter la diffusion setxid que la glibc utilise pour propager le changement à tous les threads (ce que le noyau ne prend pas en charge directement). Tout cela cesserait de fonctionner sous un modèle de filetage n: m. Ainsi, les threads std :: thread et POSIX devraient être mappés aux tâches du noyau, appliquant le modèle 1: 1.

De plus, il n'y a qu'un seul ABI GNU TLS pour C et C ++, et cela nécessite à son tour qu'il ne puisse y avoir qu'un seul type de thread dans le système, avec un pointeur de thread qui est utilisé pour atteindre éventuellement thread -données locales.

C'est pourquoi il est si peu probable que sous GNU / Linux, std :: thread utilise autre chose que les threads POSIX fournis par la glibc.


1 commentaires

Sous Linux, on peut également utiliser signalfd pour un manière beaucoup plus agréable de traiter les signaux.