在使用std::thread
测试某些功能时,一位朋友遇到了GCC的问题,我们认为值得一提的是这是否是一个GCC错误,或者这个代码可能有问题(代码打印(例如)" 7 8 9 10 1 2 3",但我们希望打印[1,10]中的每个整数:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <thread>
int main() {
int arr[10];
std::iota(std::begin(arr), std::end(arr), 1);
using itr_t = decltype(std::begin(arr));
// the function that will display each element
auto f = [] (itr_t first, itr_t last) {
while (first != last) std::cout<<*(first++)<<' ';};
// we have 3 threads so we need to figure out the ranges for each thread to show
int increment = std::distance(std::begin(arr), std::end(arr)) / 3;
auto first = std::begin(arr);
auto to = first + increment;
auto last = std::end(arr);
std::thread threads[3] = {
std::thread{f, first, to},
std::thread{f, (first = to), (to += increment)},
std::thread{f, (first = to), last} // go to last here to account for odd array sizes
};
for (auto&& t : threads) t.join();
}
以下备用代码有效:
int main()
{
std::array<int, 10> a;
std::iota(a.begin(), a.end(), 1);
using iter_t = std::array<int, 10>::iterator;
auto dist = std::distance( a.begin(), a.end() )/3;
auto first = a.begin(), to = first + dist, last = a.end();
std::function<void(iter_t, iter_t)> f =
[]( iter_t first, iter_t last ) {
while ( first != last ) { std::cout << *(first++) << ' '; }
};
std::thread threads[] {
std::thread { f, first, to },
std::thread { f, to, to + dist },
std::thread { f, to + dist, last }
};
std::for_each(
std::begin(threads),std::end(threads),
std::mem_fn(&std::thread::join));
return 0;
}
我们认为它可能与函数的arity的无序评估有关,或者只是std::thread
在复制非std::ref
- 限定参数时应该工作的方式。然后我们用Clang测试了第一个代码并且它有效(因此开始怀疑GCC错误)。
使用的编译器:GCC 4.7,Clang 3.2.1
编辑: GCC代码使用第一个版本的代码提供错误的输出,但是使用第二个版本时,它会提供正确的输出。
答案 0 :(得分:1)
从这个修改过的程序:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <thread>
#include <sstream>
int main()
{
int arr[10];
std::iota(std::begin(arr), std::end(arr), 1);
using itr_t = decltype(std::begin(arr));
// the function that will display each element
auto f = [] (itr_t first, itr_t last) {
std::stringstream ss;
ss << "**Pointer:" << first << " | " << last << std::endl;
std::cout << ss.str();
while (first != last) std::cout<<*(first++)<<' ';};
// we have 3 threads so we need to figure out the ranges for each thread to show
int increment = std::distance(std::begin(arr), std::end(arr)) / 3;
auto first = std::begin(arr);
auto to = first + increment;
auto last = std::end(arr);
std::thread threads[3] = {
std::thread{f, first, to},
#ifndef FIX
std::thread{f, (first = to), (to += increment)},
std::thread{f, (first = to), last} // go to last here to account for odd array sizes
#else
std::thread{f, to, to+increment},
std::thread{f, to+increment, last} // go to last here to account for odd array sizes
#endif
};
for (auto&& t : threads) {
t.join();
}
}
我为lambda函数first
添加了last
和f
指针的打印件,并找到了这个有趣的结果(当FIX
未定义时):
**Pointer:0x28abd8 | 0x28abe4
1 2 3 **Pointer:0x28abf0 | 0x28abf0
**Pointer:0x28abf0 | 0x28ac00
7 8 9 10
然后我为#ELSE
的{{1}}案例添加了一些代码。效果很好。
- 更新:这个结论,下面的原帖,是错误的。我的错。请参阅Josh的评论 -
我相信线程[]的第二行
#ifndef FIX
包含一个错误:内部的赋值 两对括号,可以按任何顺序进行评估 解析器。然而,第一,第二和第三个参数的赋值顺序 构造函数需要保持给定的顺序。
---更新:更正---
因此上面的调试打印结果表明GCC4.8.2(我的版本) 仍然是错误的(不是说GCC4.7),但是GCC 4.9.2修复了这个错误 Maxim Yegorushkin报道(见上文评论)。