2016-05-13 94 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