2016-05-13 91 views
1

有人可以解釋我,爲什麼如果我用下面的代碼使用lambda,那麼有時線程會嘗試插入相同的值,但它可能不正確。 (因爲對於循環我變量) 或更具體地說,爲什麼我在for循環沒有改變使用lambda?循環的C++ lambda表達式線程

謝謝

#include <iostream> 
#include <thread> 
#include <mutex> 
#include <vector> 
#include <map> 
#include <algorithm> 
#include <string> 

//#define USELAMBDA 1; 

const int threadCnt = 100; 
const int insertPerThreadCnt = 100; 
std::mutex g_map_mutex; 

void thread_function(std::string s, std::map<int, int> &map, int threadID) { 
    int baseNumber = (threadCnt * insertPerThreadCnt) * threadID; 
    for (int i = 0; i < insertPerThreadCnt; i++) { 
     // find key what is not exists for testing 
     int number = baseNumber + i; 

     g_map_mutex.lock(); 
     std::map<int, int>::iterator it = map.find(number); 
     if (map.end() == map.find(number)) { 
      map[number] = i; 
     } 
     else { 
      std::cout << "found:" << number << "/ThID:" << threadID << " Base:" << baseNumber << " i:" << i << std::endl; 
     } 
     g_map_mutex.unlock(); 
    } 
} 

void do_join(std::thread& t) { 
    t.join(); 
} 

void join_all(std::vector<std::thread>& v) { 
    std::for_each(v.begin(), v.end(), do_join); 
} 

int main() { 
    std::vector<std::thread> workers; // vector container stores threads 
    std::map <int, int> map; 
    std::string s = "Test String"; 

    for (int i = 0; i < threadCnt; ++i) { 
#ifdef USELAMBDA 
      // LAMBDA 
      workers.push_back(std::thread([&]() { 
       thread_function(s, std::ref(map), i); 
      })); 
#else 
      // NORMAL 
     workers.push_back(std::thread(thread_function, s, std::ref(map), i)); 
#endif 
    } 

    std::cout << "main thread\n"; 

#ifdef USELAMBDA 
    // Looping every thread via for_each 
    // The 3rd argument assigns a task 
    // It tells the compiler we're using lambda ([]) 
    // The lambda function takes its argument as a reference to a thread, t 
    // Then, joins one by one, and this works like barrier 
    std::for_each(workers.begin(), workers.end(), [](std::thread &t) 
    { 
     t.join(); 
    }); 
#else 
    join_all(workers); 
#endif 

    int correctSize = threadCnt * insertPerThreadCnt; 
    if (map.size() != correctSize) { 
     std::cout << "Wrong size of map:" << map.size() << ", should be: " << correctSize; 
    } 
    else { 
     std::cout << "Ready."; 
    } 

    return 0; 
} 

回答

2

你在你的代碼中的未定義的行爲。您通過引用捕獲i,並且i在循環結束後立即停止存在,並且不能保證所有線程都將在此之前完成。無論如何,UB除i將被傳遞給thread_function函數,其值不是創建lambda時的值,而是實際調用函數時獲得的值i。所以,即使你很幸運,i也沒有超出範圍,但它最有可能有不同的價值。

你的代碼改成這樣:

workers.push_back(std::thread([&map, &s, i]() { 
       thread_function(s, std::ref(map), i); 
      })); 
+0

謝謝,現在很清楚。 – user1638856