我在一个for循环中有一个lambda,其中lambda中有loop变量参数。当我运行它时,我希望输出数字0-9。但由于它是一个lambda,x不会立即得到评估。
for( int x = 0; x < n; ++x)
{
vec.push_back(thread{[&x](){
m.lock();
cout << x << endl;
m.unlock();
}});
}
输出:
0
3
3
9
等
其他语言的解决方案是创建临时变量
for( int x = 0; x < n; ++x)
{
int tmp = x;
vec.push_back(thread{[&tmp](){
m.lock();
cout << tmp << endl;
m.unlock();
}});
}
但这似乎不起作用。
请参阅Threads receiving wrong parameters
加成:
在寻找答案时,我偶然发现了这个问题 Generalizing C++11 Threads class to work with lambda 建议不要使用会使迭代器无效的容器。为什么会是/
答案 0 :(得分:11)
指定捕获时,您可以选择按值捕获和按引用捕获。您已选择通过引用捕获。通过引用捕获意味着lambda函数内的变量指的是同一个对象。这意味着对该变量的任何更改都将被共享,您还需要确保引用的对象在lambda函数的生命周期内保持不变。
您可能想要按值捕获。为此,您可以将捕获规范替换为[=]
或成为[x]
。后者确保只能访问x
,而前者允许其他变量可访问。
顺便说一句,我建议明确使用lock()
和unlock()
不,而是使用其中一个锁定保护。有了这个,你的循环体看起来像这样:
vec.push_back(std::thread{[x](){
std::lock_guard<std::mutex> kerberos(m);
std::cout << x << "\n";
}});
答案 1 :(得分:6)
如果要复制,请按值而不是引用来捕获参数:
vec.push_back(std::thread{[x](){
m.lock();
std::cout << x << std::endl;
m.unlock();
}});
这将在创建lambda对象时复制x
的值(而不是在线程启动时)。
在我寻找答案时,我偶然发现了这个问题,概括了C ++ 11 Threads类,以便与lambda一起使用,而lambda建议不要使用会使迭代器无效的容器。为什么会是/
因为它讨论的是直接使用pthreads库的完全不同的实现。您正在使用std::thread
,它旨在使用C ++。
答案 2 :(得分:3)
问题是您是通过引用捕获x。因此,当x在每个循环结束时递增时,这反映在线程中。
您希望按值捕获x,以便lambda在创建lambda时仅使用x的值。
for( int x = 0; x < n; ++x)
{
vec.push_back(thread{[x](){
m.lock();
cout << tmp << endl;
m.unlock();
}});
}