2016-04-05 8 views
0

So schrieb ich das folgende Stück Code. Es wird manchmal:C++ async Segmentfehler

Segment Fehler :: 11

Aber manchmal nicht. Können Sie erklären warum?

Ich bin auch neugierig auf die folgenden Fragen. Im Allgemeinen, wie C++ - Threads zu/wann C++ führt launch::async und launch::defferred Funktionen? Gibt es einen Nachteil von std::wait über std::get, wenn es ein future<void> ist?

std::future<void>r1, r2, r3, r4, ret; 
//sometimes seg fault, sometimes pass 
void f(int id, int t) { 
    printf("call f(%d)\n", id); 
    int ans=0; 
    if (id == 3) { 
     printf("wait 3\n"); 
     if (r1.valid()) r1.wait(); 
    } 
    if (id == 4) { 
     printf("wait 4\n"); 
     if (r1.valid()) r1.wait(); 
    } 
    printf("start f(%d)\n",id); 
    cnt[id]++; 
    for (int i=1;i<=t;i++) { 
     ans++; 
    } 
    printf("end f(%d)\n", id); 
} 

int main() { 
    r3=async(f, 3, 1e8); 
    r4=async(f, 4, 1); 

    r1=async(f, 1, 1e8); 
    r2=async(f, 2, 1e2); 


    ret=async([&]() { r1.wait();r2.wait();r3.wait();r4.wait(); printf("cnt=%d,%d,%d,%d\n", cnt[1],cnt[2],cnt[3],cnt[4]); }); 

    return 0; 
} 
+4

Deklaration von 'cnt'? 1-basierte Array-Indizierung ist ein wichtiger Punkt. –

+1

Was ist cnt? Anzahl? Warum nennst du es nicht zählen? Das ist nirgends definiert. Es würde helfen, wenn es sinnvolle Variablennamen gäbe. Und Sie beziehen sich auf r1 wenn 'id == 4 oder 3'. Bei einem asynchronen Aufruf gibt es keine Garantie, dass r1 initialisiert wird, daher kann ein Aufruf von r1.valid() einen Seg-Fehler verursachen. –

+0

@ChristopherSchneider Sie können 'valid() 'in einer standardkonstruierten Zukunft aufrufen. Es gibt nur "falsch" zurück. – Brian

Antwort

1

Es wird manchmal:

Segment Fehler :: 11

Aber manchmal nicht. Können Sie erklären warum?

Ich nehme an, dass cnt richtig deklariert ist, so dass es keinen Out-of-Bounds-Zugriff gibt. Wenn das der Fall ist, dann denke ich das Problem hier ist, dass std::future Objekte nicht Thread-sicher sind, so dass die Aufrufe r1.valid() und r1.wait() mit der Zuordnung zu r1 Rennen in main rasen. Solch ein Datenrennen verursacht undefiniertes Verhalten.

Es sieht aus wie Sie die Linie

r1=async(f, 1, 1e8); 

bis Anfang main bewegen sollte. Das Schreiben auf r1 wird dann vor den Aufrufen zu std::async für r3 und r4 sequenziert werden. Der Aufruf von std::async synchronisiert mit den entsprechenden Aufrufen von f. So erfolgt das Schreiben auf r1 vor den Aufrufen an r1.wait in f. Die future::wait Mitgliedsfunktion ist const, so dass zwei Threads sie gleichzeitig aufrufen können, ohne zu rasen.

Für kompliziertere Fälle können Sie std::packaged_task verwenden (wodurch Sie zuerst die std::future erhalten und später starten können, wenn Sie möchten) oder .

Im Allgemeinen wie funktioniert C++ zuordnet Fäden/wenn C nicht ++ ausführt launch::async und launch::defferred Funktionen?

Wenn Sie sich fragen, wie std::async wählt Strategie, die verwendet wird, wenn Sie es eine Wahl geben, die Antwort ist, dass es nicht spezifiziert ist.