2011-01-02 2 views
2

je testais au hasard std::thread dans ma machine virtuelle Linux (GCC 4.4.5-Debian) avec ce programme de test:Question sur les références de la fonction et les fils

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

Pourquoi vecteur test reste vide? Est-ce que je fais quelque chose de stupide avec des références (probablement) ou est-ce quelque chose avec bind ou un problème de threading?

Merci!

MISE À JOUR: avec l'aide combinée de Kos et villintehaspan I "fixe" le "problème":

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

qui imprime toutes les valeurs pour et semble fonctionner OK. Maintenant, une seule question demeure: est-ce juste chanceux (aka undefined behaviour (TM)) ou est la variable statique provoquant un pas silencieux de type mutex dans le code? PS: Je comprends le problème de "tuer le multithread" ici, et ce n'est pas mon point de vue. J'essaye juste de tester la robustesse de la fonctionnalité std::thread de base ...

Répondre

4

Ressemble à moi comme un problème de filetage.

Bien que je ne suis pas sûr à 100%, il convient de noter que tous les 1000 sujets:

  • font ++i sur la même valeur int (il est pas un atome opération- vous pouvez rencontrer des problèmes ici, vous peut utiliser __sync_fetch_and_add(&i,1) à la place (notez que c'est une extension gcc pas standard C++).

  • faire push_back simultanément sur un std::vector, ce qui est un conteneur de thread-safe AFAIK ... même chose pour cout Je pense que je vous crois » d besoin d'utiliser un mécanisme de verrouillage autour que (std::mutex peut-être? J'ai seulement utilisé des pthreads jusqu'ici mais je crois que c'est ce dont vous avez besoin).

Notez que ce genre de tue un avantage de l'utilisation de threads, mais qui est une conséquence du fait que vous ne devez pas utiliser plusieurs threads à la fois sur un objet non thread-safe.


---- ---- EDIT

J'ai eu un google sur cette API de filetage (non présent sur mon gcc tdm 4.5 sur Windows, malheureusement). Aparrently au lieu de:

thread(bind(f, test)) 

vous pouvez juste dire

thread(f, test) 

et passer un nombre arbitraire d'arguments de cette façon.

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

Cela devrait également résoudre votre problème de faire une copie du vecteur que je ne l'ai pas remarqué avant (+1 pour @villintehaspam ici).


En fait, une chose est nécessaire pour assurer que la copie ne soit pas créé ici:

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

fera en sorte que le vecteur est pas copié.

Wow, j'ai aussi été confus. :)

+0

Vous avez raison: l'affiche doit empêcher l'accès multithread aux variables. C'est la contrainte qui est le problème ici, mais je vote +1 car ce sera un problème après que la liaison est fixée. – villintehaspam

+1

Eh bien, il semble que l'appel 'thread (f, test)' utilise quelque chose comme 'bind' en interne, parce que je reçois le comportement de copie de vecteur ici aussi. (aussi: trop mauvais 'std :: thread' n'est pas disponible pour mingw ... le projet mingw-w64 travaille dessus, mais ce n'est pas encore fini :() – rubenvb

+0

Utile, merci beaucoup! – Tianyi

3

La liaison va réellement faire une copie du vecteur, de sorte que chaque thread push_back est sur leur propre copie (oui, que & ne va pas aider ici). Vous devez fournir les threads avec un pointeur ou similaire afin qu'ils utilisent le même vecteur. Vous devez également vous assurer d'utiliser la protection d'accès comme suggéré par Kos.

Editer: Après votre correctif pour utiliser std :: ref au lieu de faire une copie du vecteur, le problème d'accès multithread reste toujours. Je suppose que la seule raison pour laquelle vous n'obtenez aucun problème est que l'exemple est si trivial (ou peut-être que vous avez seulement essayé en mode débogage) - il n'y a aucune garantie automatique que le ++ est atomique juste parce que le int est statique.

+0

: bind' se comportent aussi de cette façon par défaut? Y a-t-il une syntaxe pour que 'std :: bind' passe le vecteur par référence, comme l'OP l'attendrait? – Kos

+1

' std :: bind (f, std :: ref (test)) '' peut-être? Juste une conjecture sauvage :) – Kos

+0

'std :: ref' fait l'affaire! – rubenvb