2013-07-02 74 views
2

我編寫了一個小型C++程序,試圖瞭解多線程如何使用std::thread工作。這裏是我的程序執行的步驟:多線程無法正常使用std :: thread(C++ 11)

  1. 初始化一個5×5整數矩陣,其中包含'Toto'類(初始化爲主)中包含的唯一值'42'。
  2. 我打印初始化的5x5矩陣。
  3. 聲明:std::vector共5線程。
  4. 我附加所有線程分別與他們的任務(threadTask方法)。每個線程將操縱一個std::vector<int>實例。
  5. 我加入所有主題。
  6. 我打印了我的5x5矩陣的新狀態。

下面是輸出:

42 42 42 42 42 
42 42 42 42 42 
42 42 42 42 42 
42 42 42 42 42 
42 42 42 42 42 

42 42 42 42 42 
42 42 42 42 42 
42 42 42 42 42 
42 42 42 42 42 
42 42 42 42 42 

它應該是:

42 42 42 42 42 
42 42 42 42 42 
42 42 42 42 42 
42 42 42 42 42 
42 42 42 42 42 

0 0 0 0 0 
1 1 1 1 1 
2 2 2 2 2 
3 3 3 3 3 
4 4 4 4 4 

下面的代碼示例:

#include <iostream> 
#include <vector> 
#include <thread> 

class  Toto 
{ 
public: 
    /* 
    ** Initialize a 5x5 matrix with the 42 value. 
    */ 
    void initData(void) 
    { 
     for (int y = 0; y < 5; y++) { 
      std::vector<int> vec; 

      for (int x = 0; x < 5; x++) { 
       vec.push_back(42); 
      } 
      this->m_data.push_back(vec); 
     } 
    } 

    /* 
    ** Display the whole matrix. 
    */ 
    void printData(void) const 
    { 
     for (int y = 0; y < 5; y++) { 
      for (int x = 0; x < 5; x++) { 
       printf("%d ", this->m_data[y][x]); 
      } 
      printf("\n"); 
     } 
     printf("\n"); 
    } 

    /* 
    ** Function attached to the thread (thread task). 
    ** Replace the original '42' value by the another one. 
    */ 
    void threadTask(std::vector<int> &list, int value) 
    { 
     for (int x = 0; x < 5; x++) { 
      list[x] = value; 
     } 
    } 

    /* 
    ** Return a sub vector reference according to the range. 
    */ 

    std::vector<int> &getDataByRange(int range) 
    { 
     return (this->m_data[range]); 
    } 

    private: 
     std::vector<std::vector<int> > m_data; 
}; 

int   main(void) 
{ 
    Toto toto; 

    toto.initData(); 

    toto.printData(); //Display the original 5x5 matrix (first display). 

    std::vector<std::thread> threadList(5); //Initialization of vector of 5 threads. 

    for (int i = 0; i < 5; i++) { //Threads initializationss 

     std::vector<int> &vec = toto.getDataByRange(i); //Get each sub-vectors reference. 
     threadList.at(i) = std::thread(&Toto::threadTask, toto, vec, i); //Each thread will be attached to a specific vector. 
    } 

    for (int j = 0; j < 5; j++) { 
     threadList.at(j).join(); 
    } 

    toto.printData(); //Second display. 
    getchar(); 

    return (0); 
} 

然而,在方法threadTask,如果我打印變量list[x],輸出是c orrect。我認爲我無法在main中打印正確的數據,因爲printData()調用位於主線程中,並且threadTask函數中的顯示是正確的,因爲該方法在其自己的線程(不是主線程)中執行。奇怪的是,這意味着在父進程中創建的所有線程都不能修改此父進程中的數據?我想我在代碼中忘記了一些東西。我真的迷失了。有人可以幫我嗎? 提前感謝您的幫助。

+8

您需要了解C++值和引用語義。 'std :: vector vec = toto.getData()[i];'製作矢量的一個副本,所以原始文件永遠不會被改變。該副本也會被複制到線程對象中,並且再也不會影響原始對象。 –

+0

我使用getDataByRange新函數更新了我的問題,該函數根據範圍返回對特定子向量的引用。所以我不會返回一個副本,而是一個參考。輸出與修改後的輸出相同。 – user1364743

+0

問題不在於getData函數,它是與std :: vector vec = ...部分。這將調用vecs拷貝構造函數,vec將是getData返回的不同對象。 作爲一個方面說明。考慮使用矢量構造函數在類構造函數中初始化矢量。 Toto():m_data(5,std :: vector (5,42)){ } 在我看來是一個更清潔的實現。 –

回答

2

我解決了我的問題。所有來自線:

threadList.at(i) = std::thread(&Toto::threadTask, toto, **vec**, i); 

必須是:

threadList.at(i) = std::thread(&Toto::threadTask, toto, **&vec**, i); 

和我的功能「threadTask」必須發生在第一個參數指針(不是一個引用)。

void threadTask(std::vector<int> *list, int value) 
    { 
     printf("b=%p\n", list); 
     getchar(); 
     for (int x = 0; x < 5; x++) { 
      (*list)[x] = value; 
     } 
    } 

我希望這個例子能幫助別人。

+4

或者,您可以像第一次嘗試一樣使用參考。但是你可以使用std :: ref作爲參數來調用std :: thread,如下所示:'std :: thread(&Toto :: threadTask,toto,std :: ref(vec),i);' – James

3

在我看來,你在寫這篇文章時所做的很多選擇都讓你的工作比必要的更加困難。特別是,您的toto類似乎(對我而言)使客戶端代碼更復雜而不是更簡單,並且無法封裝它操縱的數據。我想如果我要這樣做,我會沿着這些總體線路編寫代碼:

#include <iostream> 
#include <vector> 
#include <thread> 
#include <algorithm> 

std::ostream &operator<<(std::ostream &os, std::vector<int> const &d) { 
    for (auto const &v : d) 
     os << v << "\t"; 
    return os; 
} 

std::ostream &operator<<(std::ostream &os, std::vector <std::vector<int>> const &d) { 
    for (auto const &v : d) 
     os << v << "\n"; 
    return os; 
} 

int main(void) { 
    std::vector<std::vector<int>> d(5, std::vector<int>(5, 42)); 

    std::cout << d; 

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

    for (int i = 0; i < 5; i++) 
     threads.emplace_back([i, &d]() {std::fill(d[i].begin(), d[i].end(), i); }); 

    std::for_each(threads.begin(), threads.end(), [](std::thread &t){t.join(); }); 

    std::cout << "\n" << d; 
} 
相關問題