2016-05-19 29 views
0

Ich spiele, um zu versuchen, einem Thread eine Zeitüberschreitung zu geben. Ich versuche, std::condition_variable::wait_for zu verwenden, aber das verhält sich anders, als ich erwarten würde.Bedingung Variable Timeout nicht verstanden

Hier ist mein einfacher Code:

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

std::mutex myMutex; 

void waitSec(int seconds) 
{ 
    std::cout <<"t1 start" <<std::endl; 
    std::unique_lock<std::mutex> lock(myMutex); 
    std::this_thread::sleep_for(std::chrono::seconds(seconds)); 
    std::cout <<"t1 end" <<std::endl; 
} 

int main(void) 
{ 
    // launch thread that sleeps 10s 
    std::thread t1(waitSec,10); 
    std::this_thread::sleep_for(std::chrono::seconds(1)); 

    // wait for lock during max 1 second 
    std::condition_variable* conditionVariable = new std::condition_variable(); 
    std::cout << "before" << std::endl; 
    std::unique_lock<std::mutex> lock(myMutex); 
    conditionVariable->wait_for(lock,std::chrono::seconds(1)); 
    std::cout << "after" << std::endl; 

    t1.join(); 
} 

Ich erwarte, dass Thema T1 zum schlafen für 10 Sekunden. Da ich dem wait_for im Hauptthread 1s Timeout gebe, würde ich erwarten, dass after vor t1 end gedruckt wird.

Was stattdessen passiert ist, dass t1 für 10 Sekunden läuft, (Drucken t1 end) und nur 1s nach after gedruckt wird.

Können Sie mir erklären, warum es sich so verhält und was ich tun sollte, um mein Timeout als Timeout zu erhalten?

+0

es sieht aus wie t1 gesperrt myMutex und Haupt-Thread sollte warten, bis es veröffentlicht – DAG

Antwort

2

Das hat nichts mit condition_variable zu tun. Sie haben ein unique_lock in waitSec, bevor Sie 10 Sekunden schlafen, damit niemand in der Lage sein wird, den Mutex 10 Sekunden lang so diese Linie zu erwerben:

std::unique_lock<std::mutex> lock(myMutex); 

warten, bis zum Ende der waitSec und die Freisetzung von mutex durch die unique_lock Destruktor.

Sie müssen Ihre condition_variable erstellen, bevor ein anderer Thread Ihren Mutex gesperrt hat.

+0

danke ... das half ... also habe ich die Sperre am Anfang der Haupt erstellt. Dann, da dies den Mutex automatisch sperrt, habe ich das Entsperren genannt. Vielen Dank! – Stefano

+0

@Stefano Sie sollten den Mutex nicht manuell entsperren, die 'wait_for' (und andere' wait' Methode) von 'condition_variable' machen das für Sie (siehe http://en.cppreference.com/w/cpp/thread/ Bedingung_Variable/warten). – Holt

+0

nono ... es war, weil ich das Schloss in der Hauptsache erstellen wollte, ohne es zu verriegeln ... ich entdeckte gerade, dass ich das schaffen kann, indem ich als zweiten param std :: defer_lock – Stefano

1

Sie müssen in diesem Fall keine bedingten Variablen verwenden, da Sie nach dem Start von t1 nur 1 Sekunde im Hauptthread schlafen.

Was tatsächlich passiert ist, dass Sie den Mutex in 1 Thread gesperrt haben:

std::unique_lock<std::mutex> lock(myMutex); 

dann im Hauptthread Sie das Mutex versuchen, wieder zu sperren (nach der Rückkehr von 1 Sekunde Schlaf):

Der Haupt-Thread kann diese Sperre erst erhalten, nachdem t1 beendet ist (~ 9 Sekunden, insgesamt 10 Sekunden). Dann wird das Programm drucken „vor“ und erfolgreich Sperre erhalten und für jeden Fall für 1 Sekunde warten, denn:

conditionVariable->wait_for(lock,std::chrono::seconds(1)); 

Und da niemand wecken kann, ist (benachrichtigen) den Haupt-Thread von der Warte, so wird es nur ruhig schlafen für 1 Sekunde und druckt dann "nach"

So effektiv können Sie bekommen, was Sie nur Mutex-Locking von der Thread-Funktion entfernen möchten. Da Ihre Threads nicht miteinander interagieren/teilen Ressourcen

Wenn Sie warten müssen, war eine Sekunde oder bis Thread fertig ist, können Sie etwas tun (beachten Sie bitte, dass dieser Code nicht ideal, nur um die Grundidee zu zeigen):

std::condition_variable cv; 

void worker_thread() 
{ 
    // do something 
    // ... 
    cv.notify_one(); 
} 

int main() { 
    std::thread t1(worker_thread); 

    std::cout << "before" << std::endl; 
    std::unique_lock<std::mutex> lock(myMutex); 
    cv.wait_for(lock,std::chrono::seconds(1)); 
    std::cout << "after" << std::endl; 
} 
+0

right ... Was ich erreichen will, ist nur ein Timeout für die t1-Prozedur geben ... wenn nach 1s nicht fertig ist, sollte Haupt-Thread einfach weitermachen. Weißt du wie ich das machen könnte? – Stefano

+0

@Stefano Ich werde die Antwort aktualisieren –

1

Das passiert, weil Ihr Mutex gesperrt ist, nicht wegen der Zustandsvariablen.

in main() Sie versuchen, hier den Mutex in der 1 Zeile zu erwerben:

std::unique_lock<std::mutex> lock(myMutex); 
conditionVariable->wait_for(lock,std::chrono::seconds(1)); 

jedoch Thread t1 hier den Mutex hält:

std::unique_lock<std::mutex> lock(myMutex); 
std::this_thread::sleep_for(std::chrono::seconds(seconds)); 

So der Code in main() kann nicht fortgesetzt werden, bis der Mutex in der waitSec-Funktion, die vom t1-Thread ausgeführt wird, freigegeben wird, was geschieht, wenn die Funktion endet.

Halten Sie während des Schlafs keine Mutexe.

Verwandte Themen