Frage

Mit POSIX-Threads & C ++, ich habe eine "Insert Operation", die nur sicher einen nach dem anderen durchgeführt werden können.

Wenn ich mehrere Threads warten dann zum Einfügen mit pthread_join einen neuen Thread Laichen wenn es fertig ist. Werden sie alle erhalten sofort die „Faden komplett“ -Signal und laichen mehrere Einsätze oder ist es sicher davon ausgehen, dass der Faden, der zuerst das „Faden vollständig“ Signal empfängt, wird einen neuen Thread erzeugen, die andere von der Erstellung, neue Themen zu blockieren.

/* --- 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);

Danke für die Antworten

Das Programm ist im Grunde eine riesige Hash-Tabelle, die Anfragen von Clients über Sockets nimmt.

Jeder neue Client-Verbindung startet einen neuen Thread, aus dem sie dann mehrere Operationen durchführen können, speziell Lookups oder Einsätze. Lookups können parallel durchgeführt werden. Aber Einsätze müssen „rekombiniert“ in einem einzigen Thread werden. Man könnte sagen, dass die Lookup-Operationen ohne Laichen einen neuen Thread für die Kunden getan werden könnten, sie können jedoch eine Weile dauern, dass der Server zu sperren, neue Anforderungen fallen. Das Design versucht, Systemaufrufe und Thread-Erzeugung so weit wie möglich zu minimieren.

Aber jetzt, wo ich weiß, dass es nicht sicher ist der Weg, zuerst dachte ich, ich sollte etwas der Lage sein, zusammen schustern

Danke

War es hilfreich?

Lösung

opengroup.org auf pthread_join :

  

Die Ergebnisse mehr Anrufe gleichzeitig mit pthread_join () dem gleichen Ziel-Thread spezifiziert sind nicht definiert.

Also, sollten Sie wirklich nicht mehrere Threads haben Ihre vorherigen insertThread verbinden.

Zuerst wird, wie Sie C ++ verwenden, empfehle ich Schub. fädeln . Sie ähneln den POSIX-Modell von Threads und arbeiten auch unter Windows. Und es hilft Ihnen mit C ++, das heißt, indem sie funktions Objekte mehr verwendbar leicht.

Zweitens, warum wollen Sie zum Einfügen eines Elements einen neuen Thread starten, wenn Sie immer für die vorherige warten müssen, bis zu beenden, bevor Sie die nächste beginnen? Scheint nicht klassische Verwendung von mehreren Threads zu sein.

Obwohl ... Eine klassische Lösung dieses Problems wäre ein Arbeiter-Thread immer Arbeitsplätze von einem Ereignis-Warteschlange zu haben, und andere Threads den Betrieb auf den Event-Warteschlange hinzuzufügen.

Wenn Sie wirklich wollen einfach nur halten es mehr oder weniger so, wie Sie es jetzt haben, würden Sie dies tun:

  • Erstellen Sie eine Zustandsgröße, wie insert_finished.
  • Alle Fäden, die einen Einsatz machen wollen, warten auf die Bedingungsvariable.
  • Sobald ein Thread mit dem Einsetzen erfolgt ist, löst es die Bedingung variabel.
  • Da die Zustandsgröße einen Mutex erfordert, kann man einfach benachrichtigen alle wartenden Threads, sie alle beginnen wollen Einfügen, sondern als nur ein Thread den Mutex zu einer Zeit erwerben können, werden alle Threads tun die einfügen der Reihe nach.

Sie sollten aber darauf achten, dass die Synchronisation in einer zu Ad-hoc-Weise nicht implementiert. Da diese insert genannt wird, ich vermute, dass Sie eine Datenstruktur manipulieren wollen, so möchten Sie wahrscheinlich zuerst eine Thread-sichere Datenstruktur implementieren, anstatt die Synchronisation zwischen den Datenstruktur-Zugriffe und alle Kunden zu teilen. Ich vermute auch, dass es mehr Operationen werden dann nur insert, die richtige Synchronisation benötigt ...

Andere Tipps

nach dem Single Unix Specifcation: „Die Ergebnisse von mehreren Anrufen gleichzeitig mit pthread_join () dem gleichen Ziel-Thread spezifiziert undefiniert“

Die „normale Weg“ von einem einzigen Thread zu erreichen, die Aufgabe zu erhalten, wäre eine Bedingung Variable einzurichten (mit Angabe der zugehörigen Mutex nicht vergessen): Leerlauf-Threads warten in pthread_cond_wait () (oder pthread_cond_timedwait ()) und wenn der Faden macht die Arbeit beendet ist, wacht er eines der Ruhe diejenigen mit pthread_cond_signal nach oben ().

Ja, da die meisten Menschen sind der beste Weg zu empfehlen scheint einen Worker-Thread aus einer Warteschlange zu lesen zu haben. Einige Code-Schnipsel unten

    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;
            }

Die anderen haben bereits darauf hingewiesen, dieses undefiniert Verhalten hat. Ich würde nur hinzufügen, dass die wirklich einfachste Weg, um Ihre Aufgabe zu erfüllen (um nur ein Thread zu ermöglichen, einen Teil der Ausführung von Code) ein einfaches Mutex verwenden - Sie die Fäden müssen, dass die Ausführung von Code MUTally exklusiv sein, und das ist, wo Mutex kam sein Name: -)

Wenn Sie den Code müssen in einem bestimmten Thread lief werden (wie Java AWT), dann müssen Sie Bedingungsvariablen. Allerdings sollten Sie zweimal überlegen, ob diese Lösung lohnt sich wirklich. Stellen Sie sich vor, wie viele Kontextwechsel Sie benötigen, wenn Sie Ihre „Insert Operation“ 10000-mal pro Sekunde nennen.

Wie Sie gerade jetzt erwähnen Sie verwenden eine Hash-Tabelle mit mehrer-Lookups parallel zu Einfügungen, würde ich empfehlen, um zu überprüfen, ob Sie eine gleichzeitige Hash-Tabelle verwenden können.

Wie die genauen Look-up-Ergebnisse sind nicht deterministisch, wenn Sie Elemente sind Einfügen gleichzeitig eine solche gleichzeitige Hash-Karte kann genau das, was Sie brauchen. Ich habe keine gleichzeitigen Hash-Tabellen in C ++, obwohl verwendet, aber wie sie in Java verfügbar sind, werden Sie sicher eine Bibliothek tun dies in C ++ finden.

Die einzige Bibliothek, die ich gefunden, die Einsätze ohne Verriegelung neue Lookups unterstützt - Sonnenaufgang DD (und ich bin nicht sicher, ob es die gleichzeitige Einsätze unterstützt)

Doch der Wechsel von Google Sparse Hash Karte mehr als verdoppelt sich die Speichernutzung. Lookups sollte recht selten so anstatt zu versuchen, passiert und meine eigene Bibliothek schreiben welche die Vorteile beider kombiniert würde ich lieber nur die Tabelle sperren Aussetzung Lookups während Änderungen sicher gestellt werden.

Danke nochmal

Es scheint mir, dass Sie Einfügungen in die Hash-Tabelle serialise wollen.

Dazu wollen Sie eine Sperre -. Neue Themen Laichen

Aus Ihrer Beschreibung, die sehr ineffizient sieht aus, als Sie neu erstellen, den Einsatz Thread jedes Mal, wenn Sie etwas einfügen wollen. Die Kosten für den Faden zu schaffen ist nicht 0.

Eine weitere übliche Lösung für dieses Problem ist es, einen Einsatz Thread zu erzeugen, die in einer Warteschlange wartet (dh sitzt in einer Schleife schlafen, während die Schleife leer ist). Andere Threads dann Workitems in die Warteschlange hinzuzufügen. Der Einsatz Faden greift Elemente der Warteschlange in der Reihenfolge, wie sie (oder nach Priorität, wenn Sie möchten) hinzugefügt wurden und macht die entsprechenden Maßnahmen.

Alles, was Sie tun müssen, ist sicher, dass zusätzlich zu der Warteschlange macht geschützt ist, so dass nur ein Thread zu einer Zeit, die aktuelle Warteschlange zu modifizieren hat zugreift, und dass der Einsatz Thread eine busy wait nicht tun, sondern schläft, wenn nichts in der Warteschlange (siehe Bedingungsvariable).

Idealerweise müssen Sie nicht mehr threadpools in einem einzigen Prozess wollen, auch wenn sie unterschiedliche Operationen durchführen. Die resuability eines Threads ist eine wichtige architektonische Definition, die in einem Hauptthread erstellt pthread_join führt, dass, wenn Sie C verwenden.

Ofcourse, für einen C ++ Thread aka Thread, die Idee, die Thread-Primitiven abstrakt so zu halten, ist es jede Funktion / Operationstypen übergeben, um es verarbeiten kann.

Ein typisches Beispiel wäre ein Webserver sein, die Verbindungspools und Thread-Pools, welche Service-Verbindungen haben und sie dann weiter verarbeiten, aber alle von einem gemeinsamen Threadprozess abgeleitet werden.

SUMMARY:. VERMEIDUNG pthread_join in irgendeiner anderen Stelle als ein Hauptthread

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top