2011-01-02 11 views
2

ich zufällig std::thread in meiner virtuellen Linux-Maschine (GCC 4.4.5-Debian) mit diesem Testprogramm Testen wurde:Frage zum Funktionsreferenz und Themen

#include <algorithm> 
#include <thread> 
#include <iostream> 
#include <vector> 
#include <functional> 
using namespace std; 

static int i=0; 
void f(vector<int> &test) 
{ 
    ++i; 
    cout << "Push back called" << endl; 
    test.push_back(i); 
} 

int main() 
{ 
    vector<thread> t; 
    vector<int> test; 
    for(int i=0; i<1000; ++i) 
    { 
     t.push_back(thread(bind(f, test))); 
    } 
    for(auto it = t.begin(); it != t.end(); ++it) 
    { 
     (*it).join(); 
    } 
    cout << test.size() << endl; 
    for(auto it = test.begin(); it != test.end(); ++it) 
    { 
     cout << *it << endl; 
    } 

    return 0; 
} 

Warum Vektor test leer bleiben? Mache ich etwas Dummes mit Referenzen (wahrscheinlich) oder ist es etwas mit bind oder ein Threading-Problem?

Danke!

UPDATE:

#include <algorithm> 
#include <thread> 
#include <iostream> 
#include <vector> 
#include <functional> 
using namespace std; 

static int i=0; 
void f(vector<int> &test) 
{ 
    ++i; 
    test.push_back(i); 
} 

int main() 
{ 
    vector<thread> t; 
    vector<int> test; 
    for(int i=0; i<1000; ++i) 
    { 
     t.push_back(thread(f, std::ref(test))); 
    } 
    for(auto it = t.begin(); it != t.end(); ++it) 
    { 
     (*it).join(); 
    } 
    cout << test.size() << endl; 
    for(auto it = test.begin(); it != test.end(); ++it) 
    { 
     cout << *it << endl; 
    } 

    return 0; 
} 

, die alle Werte um druckt und scheint gut zu funktionieren: mit der kombinierten Hilfe von Kos und villintehaspan ich das "Problem" "fixiert". Jetzt bleibt nur eine Frage: Ist das nur ein Glück (undefiniertes Verhalten (TM)) oder ist die statische Variable ein stiller Mutex-ähnlicher Schritt im Code?

PS: Ich verstehe das Problem "Multithreadingness" hier, und das ist nicht mein Punkt. Ich versuche nur, um die Robustheit der grundlegenden std::thread Funktionalität zu testen ...

Antwort

4

Sieht für mich wie ein Threading-Problem.

Während ich nicht 100% sicher bin, ist zu beachten, dass alle 1000 Themen:

  • tun ++i auf dem gleichen int-Wert (es ist nicht ein Atom Betrieb- Sie Probleme hier auftreten können, Sie können __sync_fetch_and_add(&i,1) statt (beachten Sie, dass es sich um eine gcc-Erweiterung ist nicht Standard C++);.

  • tun push_back gleichzeitig auf einem std::vector, die AFAIK kein Thread-sichere Behälter ist ... das Gleiche gilt für cout ich glaube, ich glaube, Sie‘ d müssen Sie einen Verriegelungsmechanismus verwenden dass (std::mutex vielleicht? Ich habe bisher nur Pthreads benutzt, aber ich glaube es ist was du brauchst).

Beachten Sie, dass diese Art von tötet keinen Nutzen von Threads hier verwendet wird, aber das ist eine Folge der Tatsache, dass Sie nicht mehrere Threads auf einmal auf einem nicht-Thread-sicher verwenden soll.


---- ---- EDIT

hatte ich eine Google auf diesem Threading-API (nicht vorhanden auf meinem tdm gcc 4.5 auf Windows, leider). Aparrently statt:

thread(bind(f, test)) 

können Sie einfach sagen

thread(f, test) 

und eine beliebige Anzahl von Argumenten auf diese Weise passieren.

Quelle: http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=422

Dies sollte auch Ihr Problem mit Erstellen einer Kopie des Vektors lösen, die ich vorher nicht (+1 für @villintehaspam hier) bemerkt haben.


Eigentlich eine Sache benötigt die Kopie, um sicherzustellen, nicht hier erstellt:

thread(f, std::ref(test)) 

wird sicherstellen, dass der Vektor nicht kopiert wird.

Wow, ich habe auch verwirrt. :)

+0

Sie haben Recht, dass das Poster Multithread-Zugriff auf die Variablen verhindern soll. Es ist die Bindung, die hier das Problem ist, aber ich stimme +1, da dies ein Problem sein wird, nachdem die Bindung behoben wurde. – villintehaspam

+1

Nun, es scheint, dass der 'thread (f, test)' Aufruf intern so etwas wie 'bind' verwendet, weil ich auch hier das Vektorkopierverhalten bekomme. (auch: zu schade 'std :: thread' ist nicht für mingw verfügbar ... das mingw-w64 projekt arbeitet daran, aber es ist noch nicht fertig :() – rubenvb

+0

Hilfreich, vielen dank! – Tianyi

3

Die Bindung wird tatsächlich eine Kopie des Vektors, so dass jeder Thread push_back auf ihre eigene Kopie (ja, dass & wird hier nicht helfen). Sie müssen die Threads mit einem Zeiger oder ähnlichem versehen, damit sie denselben Vektor verwenden. Sie sollten auch den Zugriffsschutz wie von Kos empfohlen verwenden.

Edit: Nach Ihrem Fix, um std :: ref zu verwenden, anstatt eine Kopie des Vektors zu erstellen, bleibt das Multithread-Zugriffsproblem bestehen. Meine Vermutung ist, dass der einzige Grund, warum Sie im Moment keine Probleme bekommen, ist, dass das Beispiel so trivial ist (oder Sie haben es nur im Debug-Modus versucht) - es gibt keine automatische Garantie, dass das ++ atomar ist, nur weil int ist statisch.

+0

Hat' boost: : bind 'verhält sich auch standardmäßig so? Gibt es eine Syntax, die' std :: bind' veranlasst, den Vektor als Referenz zu übergeben, wie das OP erwarten würde? – Kos

+1

'std :: bind (f, std :: ref (test)) "vielleicht? Nur eine wilde Vermutung :) – Kos

+0

' std :: ref "macht den Trick! – rubenvb