当前位置:  开发笔记 > 编程语言 > 正文

用于std :: thread的scoped线程包装器

如何解决《用于std::thread的scoped线程包装器》经验,为你挑选了1个好方法。

我正在尝试制作一个范围的线程.

#include 
#include 

class ScopedThread {
 public:
    template< class Function, class... Args>
    explicit ScopedThread( int id, Function&& f, Args&&... args)
        : m_thread( std::ref(f), std::forward(args)...)
        , id(std::move(id)) {
    }



    int getId() const { return id; }

    ~ScopedThread() { m_thread.join(); }
 private:
    std::thread m_thread;
    int id;

};

class Worker {
 public:
    Worker(int id): thd(id, &Worker::work, this) { }

    void work() {
       for( int i = 0; i < 10; i++)
        std::cout << "I am working" << std::endl;
    }


 private:
    ScopedThread thd;
};

int main() {
    Worker(1);
    Worker(2);
    Worker(3);
    Worker(4);
}

当我运行代码时,它会转储核心.

#0  0x00007ffcfbbc6380 in ?? ()
#1  0x00000000004026c9 in std::_Mem_fn::operator()<, void>(Worker*) const (this=0x7f0b43551de0, __object=0x7ffcfbbc63c0)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:601
#2  0x00000000004025cd in std::__invoke (__f=@0x7ffcfbbc6360: (void (Worker::*)(Worker * const)) 0x7ffcfbbc6380, this adjustment 4198629,
    __args=) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:247
#3  0x0000000000402532 in std::reference_wrapper::operator()(Worker*&&) const (this=0x1b27048,
    __args=) at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:467
#4  0x00000000004024d2 in std::_Bind_simple (Worker*)>::_M_invoke<0ul>(std::_Index_tuple<0ul>) (this=0x1b27040)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1731
#5  0x0000000000402485 in std::_Bind_simple (Worker*)>::operator()() (this=0x1b27040)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/functional:1720
#6  0x0000000000402119 in std::thread::_Impl (Worker*)> >::_M_run() (this=0x1b27028)
    at /usr/bin/../lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/thread:115
#7  0x00007f0b44103a60 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#8  0x00007f0b43920184 in start_thread (arg=0x7f0b43552700) at pthread_create.c:312
#9  0x00007f0b4364d37d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111

有人能告诉我如何将成员函数和参数转发给底层的std :: thread类?我观察到,分段错误只出现在clang ++中,而不是gcc中.

我的目标是使包装类完全可以用std :: thread类替换.Wrapper类为线程id获取一个新参数.



1> Vittorio Rom..:

您的实施有几个问题ScopedThread.

    没有必要Function&& f单独处理.只需处理它作为args...包的一部分.

    没有必要搬家id.

    template< class... Args>
    explicit ScopedThread( int id, Args&&... args)
        : m_thread( std::forward(args)...)
        , id(id) {
    }
    

    在调用之前,您应该确保您的线程可以连接.join().

    ~ScopedThread() { if(m_thread.joinable()) m_thread.join(); }
    

应用这些更改可防止clang ++上的分段错误.


罪魁祸首是std::ref(f)- 你正在创建一个临时的reference_wrapper并将它传递给用来调用它std::thread的构造函数std::invoke.

根据g++UndefinedBehaviorSanitizer:

/usr/local/gcc-head/include/c++/7.0.1/bits/invoke.h:73:46:

运行时错误:对于'struct Worker'类型的成员调用未对齐的地址0x7fff939ec8d3,这需要8字节对齐

问题是,你正在创建一个临时参考使用std::ref(f),其中临时是&Worker::work.

复制f而不是使用std::ref不会导致任何段错误或UndefinedBehaviorSanitizer诊断.

推荐阅读
Gbom2402851125
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有