2016-02-25 23 views
8

Sto cercando di aggiungere un ciclo semplice con i thread, ma ancora qualcosa non sta funzionando. Ho controllato una serie di motivi e non riesco a trovare alcuna soluzione.Errori con multithreading nel ciclo for

Ho una classe semplice con due metodi A() e B(). Dall'altra classe, chiamo il metodo A(). Questo è come appare:

void MyClass::A() 
{ 
    std::vector<std::thread> threads; 
    for(int i=0;i<2;i++) 
    { 
     threads.push_back(std::thread(&MyClass::B, this)); 
    } 
    for(auto &t : threads) 
    { 
     if(t.joinable()) 
      t.join(); 
    } 
} 

void MyClass::B() 
{ 
} 

Eppure sto ancora ricevendo alcuni errori:

#0 ?? ??() (??:??) 
#1 00446D62 pthread_create_wrapper() (??:??) 
#2 75327FB0 msvcrt!_cexit() (C:\Windows\SysWOW64\msvcrt.dll:??) 
#3 040C8710 ??() (??:??) 
#4 753280F5 msvcrt!_beginthreadex() (C:\Windows\SysWOW64\msvcrt.dll:??) 
#5 75B17C04 KERNEL32!BaseThreadInitThunk() (C:\Windows\SysWOW64\kernel32.dll:??) 
#6 77ABAB8F ??() (??:??) 
#7 77ABAB5A ??() (??:??) 
#8 ?? ??() (??:??) 

Qualcuno ha idea di cosa è sbagliato?

Solo per aggiungere un'altra cosa. Questo:

void MyClass::A() 
{ 
    std::thread t(&MyClass::B, this); 
    if(t.joinable()) 
     t.join(); 
} 

void MyClass::B() 
{ 
} 

funziona senza problemi.

+0

@davmac Ci stavo anche pensando, prendendo in considerazione qualcosa come 'std :: move()', ma guardando attraverso molti esempi online e post SO penso che sia possibile. – sebap123

+0

Vorrei usare 'threads.emplace_back (std :: move (std :: thread (& MyClass :: B, this)));' – knivil

+1

@davmac, OP non sta copiando, OP si sta muovendo. – SergeyA

risposta

1

Suggerirei di usare new e un puntatore invece di riferimenti.

Mentre i riferimenti sono carini, il numero di commenti illustra la confusione causata in questo caso. Come puoi dimostrare che l'implementazione della libreria di terze parti (ad esempio std) funzionerà nel modo in cui ti aspetti? e attraverso le piattaforme?

se si utilizza:

std::vector<std::thread *> threads; 

e:

threads.push_back(new std::thread(&MyClass::B(), this)); 

E, naturalmente, con un 'cancella' quando si è fatto con il filo, poi la confusione viene eliminato.

Inoltre, il codice sta caricando l'istanza SAME della classe "A" sull'array per tutti i thread. Se si utilizzano variabili membro in A all'interno della funzione 'B', senza alcun tipo di protezione multithread (es. Semafori, sezioni critiche, ecc.) Il codice non funzionerà mai correttamente. L'utilizzo di un 'nuovo' per la creazione dell'istanza del thread evita i problemi che i costruttori di copia o gli operatori di assegnazione causano con la classe vector.

#include <SDKDDKVer.h> 
#include <vector> 
#include <thread> 
#include <iostream> 

using namespace std; 

class MyClass { 
    public: 
    void A() { 
     cout << "starting\n"; 
     cout << "creating threads\n"; 
     vector<thread*> threads; 
     for (int i = 0;i<4;i++) { 
     thread * t = new thread(&MyClass::B, this); 
     cout << "creating thread "<<t<<" id:"<<t->get_id()<<"\n"; 
     threads.push_back(t); 
     } 
     cout << "waiting for threads to complete\n"; 
     for (thread * t : threads) { 
     if (t->joinable()) { 
      t->join(); 
     } 
     cout << "destroying "<<t<<"\n"; 
     delete t; 
     } 
     cout << "done\n"; 
    } 

    void B() { 
    // now it would be very bad if this function used 
    // member variables that are part of this instance of A 
    cout << "hello from " << this << "\n"; 
    } 
}; 

int main() { 
    MyClass cls; 
    cls.A(); 
    return 0; 
}