2017-01-20 1 views
2

In meiner Haupt-Funktion zu verlassen gibt es einige Objekte, die Arbeiten im Hintergrund zu tun, bis der destructor wie im folgenden Ausschnitt aufgerufen:C++ - Die beste Weg vom Haupt

#include <iostream> 

class MyBackground { 
public: 
    MyBackground() 
    { 
     m_workerThread = std::thread(&MyBackground::work, this); 
    } 
    ~MyBackground() 
    { 
     g_exit = true; 
     workerThread.join(); 
    } 

private: 
    void work() 
    { 
     while(!m_exit); 
    } 

private: 
    std::atomic<bool> m_exit{false}; 
    std::thread m_workerThread; 
}; 


int main(int argc, char* argv[]) 
{ 
    MyBackground object; 

    // here ther's some async background work 
    return EXIT_SUCCESS; 

    // ~MyBackground -> here threads are stopped 
} 

Ich muß einen Weg Haupt zu blockieren, bis ein externes Signal tritt auf. Mein erster Versuch war etwas in der Art:

#include <csignal> 
#include <iostream> 
#include <thread> 

using namespace std 

atomic<bool> g_Exit{false}; 

void signalExit(int) 
{ 
    g_Exit = true; 
} 

int main(int argc, char* argv[]) 
{ 
    signal(SIGINT, signalExit); 
    signal(SIGTERM, signalExit); 

    MyBackground object; 

    while (!g_Exit) 
     this_thread::sleep_for(chrono::seconds{1}); 

    // here ther's some async background work 
    return EXIT_SUCCESS; 

    // ~MyBackground -> here threads are stopped 
} 

Aber ich bin mir nicht sicher, ob das gut funktioniert. Ich dachte, ist eine bessere Nutzung condition_variables wie der folgende Ausschnitt:

#include <csignal> 
#include <iostream> 
#include <thread> 
#include <mutex> 
#include <condition_variable> 

using namespace std 

bool g_exitFlag = false; 
condition_variable g_exitCondition; 
mutex g_exitMutex; 

using Lock = unique_lock<mutex>; 

void signalExit(int) 
{ 
    Lock lock{g_exitMutex}; 
    g_exitFlag = true; 
    g_exitCondition.notify_one(); 
} 

int main(int argc, char* argv[]) 
{ 
    signal(SIGINT, signalExit); 
    signal(SIGTERM, signalExit); 

    MyBackground object; 

    Lock lock{g_exitMutex}; 
    g_exitCondition.wait(lock, [](){return g_exitFlag;}); 

    // here ther's some async background work 
    return EXIT_SUCCESS; 

    // ~MyBackground -> here threads are stopped 
} 

Welche der besten Implementierungen korrekt ist. Sind sie richtig? Ich bin kein "Experte" in der Multithreading-Programmierung.

+1

Was ist mit [sigwait] (http://man7.org/linux/man-pages/man3/sigwait.3.html)? –

+0

Das ist gut, schade, das ist nicht auf Windows auch –

+1

Ich denke, die Bedingung Variable Lösung ist besser, weil es Umfragen vermeidet. Das Polling ist eine nicht optimale Lösung, da es erfordert, dass die CPU regelmäßig aufwacht, und fügt dem Shutdown-Prozess eine unnötige Verzögerung hinzu. –

Antwort

4

Warum nicht ein etwas anderes Design, bei dem Ihr Hintergrund-Worker-Thread nicht von der Klasse MyBackground erstellt und zerstört wird, aber der Thread in der main-Funktion erstellt wird? Dann kann die main Funktion join einfach auf dem Thread aufrufen, bevor es beendet wird, und es wird blockieren, bis der Hintergrundthread beendet ist.

So etwas wie

class MyBackground { 
public: 
    void work() 
    { 
     while(!m_exit) 
     { 
      // Do background work 
     } 
    } 

private: 
    std::atomic<bool> m_exit{false}; 
}; 

int main() 
{ 
    MyBackground background; 
    std::thread background_thread(&MyBackground::work, background); 

    // Do foreground work 

    background.join(); // Wait for background to exit 

    // Implicit return 
} 

Eine andere Lösung, wenn der Thread soll fortgesetzt wird, wenn die main Funktion zurückkehrt, zu detach ist der rote Faden. Dann wird es unabhängig vom Hauptthread funktionieren und der Prozess wird nicht wirklich beendet, bis der Thread beendet wurde.

Beachten Sie, dass dies erfordert die main Funktion nicht nur zurückgeben oder , da dies den Prozess einschließlich der Beseitigung aller Threads beendet. Stattdessen müssen Sie nur den Hauptthread beenden. Leider ist dies mit der Standard-C++ - Thread-Schnittstelle nicht möglich, Sie müssen jedoch plattformspezifische Funktionen verwenden. Zum Beispiel auf POSIX-Systemen (wie MacOS und Linux) verwenden Sie pthread_exit.

+0

Ja, so haben Multithread-Programme, die ich gesehen habe, damit zu tun gehabt. –

+0

Ich mag diese Lösung nicht, weil ich meine Anwendung glatt verlassen möchte, wenn ein externes Signal triggert (wie 'SIGINT' oder' SIGTERM') –

+0

@ elvis.dukaj Dann sieht die erste Lösung mit der einzelnen 'atomaren 'globalen Variable aus wie die beste (und sicherlich die einfachste) Lösung für mich. –

0

Sie können einfach eine std :: weak_ptr in main() verwenden, um zu überprüfen, ob die Zählung der starken ref null ist, um zu beenden. Übergeben Sie den einzigen starken Referenzzeiger an andere Threads, um main() problemlos zu beenden. Verwenden Sie stattdessen std :: conditon_variable, um das Schließen von Threads zu vermeiden, die auf condition_variable warten, um die CPU-Auslastung während der Abfrage zu reduzieren, um zu überprüfen, ob der Wert von weak_ptr abläuft oder nicht.

void worker_thread(std::shared_ptr<int>& pulse) 
{ 
    // do something 
    std::this_thread::sleep_for(std::chrono::seconds(2)); 

    pulse.reset(); // reset to terminate main() too from any other threads 
    } 

void main() 
{ 
    std::shared_ptr<int> pulse = std::make_shared<int>(1); 
    std::weak_ptr<int> weak_pulse(pulse); 

    std::thread([&](){ worker_thread(pulse); }).detach(); 

    while (auto strong = weak_pulse.lock()) 
     std::this_thread::sleep_for(std::chrono::milliseconds(100)); 

} 
Verwandte Themen