Question

Utilisation des threads POSIX & amp; C ++, je dispose d'une "opération d'insertion". qui ne peut être fait en toute sécurité qu'un à la fois.

Si plusieurs threads attendent d'être insérés à l'aide de pthread_join, un nouveau thread est alors créé. quand ça finit. Vont-ils tous recevoir le "fil complet"? signaler en une fois et générer plusieurs insertions ou est-il prudent de supposer que le fil qui reçoit le "fil terminé"? signal en premier créera un nouveau thread empêchant les autres de créer de nouveaux threads.

/* --- GLOBAL --- */
pthread_t insertThread;



/* --- DIFFERENT THREADS --- */
// Wait for Current insert to finish
pthread_join(insertThread, NULL); 

// Done start a new one
pthread_create(&insertThread, NULL, Insert, Data);

Merci pour les réponses

Le programme est essentiellement une énorme table de hachage qui prend les demandes des clients via Sockets.

Chaque nouvelle connexion client génère un nouveau thread à partir duquel elle peut effectuer plusieurs opérations, notamment des recherches ou des insertions. les recherches peuvent être effectuées en parallèle. Mais les inserts doivent être "re-combinés". en un seul fil. Vous pouvez dire que les opérations de recherche peuvent être effectuées sans créer de nouveau thread pour le client, mais qu'elles peuvent prendre un certain temps, entraînant le verrouillage du serveur et le rejet de nouvelles demandes. La conception essaie de minimiser autant que possible les appels système et la création de threads.

Mais maintenant que je sais que ce n'est pas sûr de la façon dont je pensais que je devrais être capable de bricoler quelque chose ensemble

Merci

Était-ce utile?

La solution

De opengroup.org sur pthread_join :

  

Les résultats de plusieurs appels simultanés à pthread_join () spécifiant le même thread cible ne sont pas définis.

Donc, vous ne devriez vraiment pas avoir plusieurs threads rejoignant votre précédent insertThread.

Tout d'abord, lorsque vous utilisez le C ++, je vous recommande de boost. fil . Ils ressemblent au modèle de thread POSIX et fonctionnent également sous Windows. Et cela vous aide avec C ++, c’est-à-dire en rendant les objets de fonction plus facilement utilisables.

Deuxièmement, pourquoi voulez-vous commencer un nouveau fil pour insérer un élément, alors que vous devez toujours attendre que le précédent se termine avant de commencer le suivant? Ne semble pas être une utilisation classique de plusieurs threads.

Bien que ... Une solution classique à ce problème consisterait à faire en sorte qu'un thread de travail récupère les travaux d'une file d'attente d'événements et que d'autres threads publient l'opération dans la file d'attente d'événements.

Si vous voulez vraiment le conserver plus ou moins comme vous l'avez maintenant, vous devez le faire:

  • Créez une variable de condition, telle que insert_finished .
  • Tous les threads souhaitant effectuer une insertion attendent la variable de condition.
  • Dès qu'un thread est inséré, la variable de condition est déclenchée.
  • Comme la variable de condition nécessite un mutex, vous pouvez simplement notifier tous les threads en attente. Ils veulent tous commencer à insérer, mais comme un seul thread peut acquérir le mutex à la fois, tous les threads effectueront la tâche. insérer séquentiellement.

Mais vous devez veiller à ce que votre synchronisation ne soit pas implémentée de manière trop ad-hoc. Comme cela s'appelle insert , je suppose que vous souhaitez manipuler une structure de données. Par conséquent, vous voudrez probablement d'abord mettre en place une structure de données sécurisée pour les threads, au lieu de partager la synchronisation entre les accès à la structure de données. et tous les clients. Je pense aussi qu'il y aura plus d'opérations que juste insérer , ce qui nécessitera une synchronisation appropriée ...

Autres conseils

Selon la spécification Single Unix: "Les résultats de plusieurs appels simultanés à pthread_join () spécifiant le même thread cible ne sont pas définis."

La "manière normale" pour obtenir un seul thread pour obtenir la tâche serait de définir une variable de condition (n'oubliez pas le mutex associé): les threads inactifs attendent dans pthread_cond_wait () (ou pthread_cond_timedwait ()), et lorsque le thread effectuant le travail est terminé , il réveille l’un des inactifs avec pthread_cond_signal ().

Oui, comme le recommandent la plupart des gens, il semble qu'un thread de travail lise depuis une file d'attente. Quelques extraits de code ci-dessous

    pthread_t       insertThread = NULL;
    pthread_mutex_t insertConditionNewMutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_mutex_t insertConditionDoneMutex    = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t  insertConditionNew      = PTHREAD_COND_INITIALIZER;
    pthread_cond_t  insertConditionDone     = PTHREAD_COND_INITIALIZER;

       //Thread for new incoming connection
        void * newBatchInsert()
        {
           for(each Word)
           {
                            //Push It into the queue
                            pthread_mutex_lock(&lexicon[newPendingWord->length - 1]->insertQueueMutex);
                                lexicon[newPendingWord->length - 1]->insertQueue.push(newPendingWord);
                            pthread_mutex_unlock(&lexicon[newPendingWord->length - 1]->insertQueueMutex);

           }

                    //Send signal to worker Thread
                    pthread_mutex_lock(&insertConditionNewMutex);
                        pthread_cond_signal(&insertConditionNew);
                    pthread_mutex_unlock(&insertConditionNewMutex);

                    //Wait Until it's finished
                    pthread_cond_wait(&insertConditionDone, &insertConditionDoneMutex);

        }


            //Worker thread
            void * insertWorker(void *)
            {

                while(1)        
                {

                    pthread_cond_wait(&insertConditionNew, &insertConditionNewMutex);

                    for (int ii = 0; ii < maxWordLength; ++ii)
                    {                   
                            while (!lexicon[ii]->insertQueue.empty())
                            {

                                queueNode * newPendingWord = lexicon[ii]->insertQueue.front();


                                lexicon[ii]->insert(newPendingWord->word);

                                pthread_mutex_lock(&lexicon[ii]->insertQueueMutex);
                                lexicon[ii]->insertQueue.pop();
                                pthread_mutex_unlock(&lexicon[ii]->insertQueueMutex);

                            }

                    }

                    //Send signal that it's done
                    pthread_mutex_lock(&insertConditionDoneMutex);
                        pthread_cond_broadcast(&insertConditionDone);
                    pthread_mutex_unlock(&insertConditionDoneMutex);

                }

            }

            int main(int argc, char * const argv[]) 
            {

                pthread_create(&insertThread, NULL, &insertWorker, NULL);


                lexiconServer = new server(serverPort, (void *) newBatchInsert);

                return 0;
            }

Les autres ont déjà signalé que ce comportement est indéfini. J'ajouterais simplement que le moyen le plus simple d'accomplir votre tâche (pour n'autoriser qu'un seul thread exécutant une partie du code) consiste à utiliser un simple mutex - vous avez besoin que les threads exécutant ce code soient MUTAL EXclusive, et c'est là que mutex est venu son nom: -)

Si vous souhaitez que le code soit exécuté dans un thread spécifique (tel que Java AWT), vous avez besoin de variables conditionnelles. Cependant, vous devriez réfléchir à deux fois si cette solution est réellement rentable. Imaginez combien de commutateurs de contexte vous avez besoin si vous appelez votre "opération d'insertion". 10000 fois par seconde.

Comme vous venez de mentionner que vous utilisez une table de hachage avec plusieurs recherches parallèles aux insertions, je vous conseillerais de vérifier si vous pouvez utiliser une table de hachage simultanée.

Étant donné que les résultats de recherche exacts ne sont pas déterministes lorsque vous insérez des éléments simultanément, une telle carte de hachage simultanée peut être exactement ce dont vous avez besoin. Je n'ai cependant pas utilisé de tables de hachage concurrentes en C ++, mais comme elles sont disponibles en Java, vous trouverez certainement une bibliothèque qui le fait en C ++.

La seule bibliothèque que j'ai trouvée qui supporte les insertions sans verrouiller les nouvelles recherches - Sunrise DD (et je ne sais pas s'il prend en charge les insertions simultanées)

Cependant, le passage de la carte Sparse Hash de Google double à plus que l'utilisation de la mémoire. Les recherches devraient être assez rares alors plutôt que d'essayer d'écrire ma propre bibliothèque qui combine les avantages des deux, je préférerais simplement verrouiller la table en suspendant les recherches pendant que les modifications sont effectuées en toute sécurité.

Merci encore

Il me semble que vous souhaitez sérialiser les insertions dans la table de hachage.

Pour cela, vous voulez un verrou et non pas créer de nouveaux threads.

D'après votre description, cela semble très inefficace lorsque vous recréez le fil d'insertion à chaque fois que vous souhaitez insérer quelque chose. Le coût de la création du fil n'est pas égal à 0.

Une solution plus courante à ce problème consiste à créer un thread d’insertion qui attend une file d’attente (c’est-à-dire assis dans une boucle en veille tant que la boucle est vide). D'autres threads ajoutent ensuite des éléments de travail à la file d'attente. Le fil d'insertion choisit les éléments de la file d'attente dans l'ordre dans lequel ils ont été ajoutés (ou par priorité si vous le souhaitez) et effectue l'action appropriée.

Tout ce que vous avez à faire est de vous assurer que les ajouts à la file d'attente sont protégés de manière à ce qu'un seul thread à la fois ait accès à la modification de la file d'attente réelle, et que le thread d'insertion n'effectue pas une attente occupée, mais qu'il dorme plutôt quand rien ne se produit. dans la file d'attente (voir variable de condition).

Idéalement, vous ne voulez pas avoir plusieurs pools de threads dans un même processus, même s'ils effectuent des opérations différentes. La possibilité de créer un thread est une définition architecturale importante, ce qui conduit à la création de pthread_join dans un thread principal si vous utilisez C.

Bien sûr, pour un pool de threads C ++, également appelé ThreadFactory, l’idée est de garder les primitives de thread abstraites de manière à ce qu’il puisse gérer n’importe quel type de fonction / opération qui lui est transmis.

Un exemple typique serait un serveur Web qui aura des pools de connexions et des pools de threads qui serviront les connexions et les traiteront ensuite, mais tous sont dérivés d'un processus de pool de threads commun.

SOMMAIRE: ÉVITER PTHREAD_JOIN DANS un emplacement autre qu'un thread principal.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top