(优化?)有关GCC std :: thread的错误 [英] (Optimization?) Bug regarding GCC std::thread

查看:195
本文介绍了(优化?)有关GCC std :: thread的错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用 std :: thread 测试某些功能时,一个朋友遇到了GCC的问题,我们认为这是值得问的,如果这是一个GCC错误,或者有错误使用这个代码(代码打印(例如)7 8 9 10 1 2 3,但我们希望打印[1,10]中的每个整数):

While testing some functionality with std::thread, a friend encountered a problem with GCC and we thought it's worth asking if this is a GCC bug or perhaps there's something wrong with this code (the code prints (for example) "7 8 9 10 1 2 3", but we expect every integer in [1,10] to be printed):

#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 -qualified参数时工作。然后我们用Clang测试第一个代码,它工作(因此开始怀疑一个GCC错误)。

We thought maybe its got something to do with the unsequenced evaluation of function's arity or its just the way std::thread is supposed to work when copying non-std::ref-qualified arguments. We then tested the first code with Clang and it works (and so started to suspect a GCC bug).

使用的编译器:GCC 4.7,Clang 3.2.1

Compiler used: GCC 4.7, Clang 3.2.1

EDIT: GCC代码为第一个版本的代码提供了错误的输出,但是第二个版本提供了正确的输出。

The GCC code gives the wrong output with the first version of the code, but with the second version it gives the correct output.

推荐答案

从这个修改的程序:

#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函数 f 的指针,并找到这个有趣的结果 FIX 未定义):

I add the prints of the first and last pointer for lambda function f, and find this interesting results (when FIX is undefined):

**Pointer:0x28abd8 | 0x28abe4
1 2 3 **Pointer:0x28abf0 | 0x28abf0
**Pointer:0x28abf0 | 0x28ac00
7 8 9 10

然后我为 #ELSE 大小写为 #ifndef FIX 。它工作得很好。

Then I add some code for the #ELSE case for the #ifndef FIX. It works well.

- 更新:这个结论,下面的原始帖子是错误的。我的错。请参阅下面的Josh的注释 -


我相信第二行 std :: thread {f第一个=到),(到+ =
增量)},
的线程[]包含一个错误:
内的赋值两对括号, order,由
解析器。然而,
构造函数的第一,第二和第三个参数的赋值顺序需要保持给定的顺序。

I believe the 2nd line std::thread{f, (first = to), (to += increment)}, of threads[] contains a bug: The assignment inside the two pairs of parenthesis, can be evaluated in any order, by the parser. Yet the assignment order of 1st, 2nd and 3rd argument of the constructor needs to keep the order as given.

strong> --- Update:corrected ---

--- Update: corrected ---

因此,上述调试打印结果表明GCC4.8.2(我的版本)
仍然是buggy(不是说GCC4.7),但是GCC 4.9.2修复了这个bug,如Maxim Yegorushkin报告的
(见上面的注释)。

Thus the above debug printing results suggest that GCC4.8.2 (my version) is still buggy (not to say GCC4.7), but GCC 4.9.2 fixes this bug, as reported by Maxim Yegorushkin (see comment above).

这篇关于(优化?)有关GCC std :: thread的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆