C++ 11:在构造函数中使用线程初始化执行函数成员的类中的std :: thread

Moo*_*oks 14 c++ multithreading stl c++11

我正在尝试使用C++ 11中的std :: thread.如果可以在执行其某个函数成员的类中使用std :: thread,我找不到任何地方.考虑下面的例子......在我的尝试(下面)中,函数是run().

我使用-std = c ++ 0x标志用gcc-4.4编译.

#ifndef RUNNABLE_H
#define RUNNABLE_H

#include <thread>

class Runnable
{
    public:
        Runnable() : m_stop(false) {m_thread = std::thread(Runnable::run,this); }
        virtual ~Runnable() { stop(); }
        void stop() { m_stop = false; m_thread.join(); }
    protected:
        virtual void run() = 0;
        bool m_stop;
    private:
        std::thread m_thread;
};


class myThread : public Runnable{
protected:
    void run() { while(!m_stop){ /* do something... */ }; }
};

#endif // RUNNABLE_H
Run Code Online (Sandbox Code Playgroud)

我收到这个错误和其他人:(有和没有$ this相同的错误)

Runnable.h|9|error: no matching function for call to ‘std::thread::thread(<unresolved overloaded function type>, Runnable* const)’|
Run Code Online (Sandbox Code Playgroud)

传递指针时.

Runnable.h|9|error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say ‘&Runnable::run’|
Run Code Online (Sandbox Code Playgroud)

ild*_*arn 17

这里有一些代码要仔细考虑:

#ifndef RUNNABLE_H
#define RUNNABLE_H

#include <atomic>
#include <thread>

class Runnable
{
public:
    Runnable() : m_stop(), m_thread() { }
    virtual ~Runnable() { try { stop(); } catch(...) { /*??*/ } }

    Runnable(Runnable const&) = delete;
    Runnable& operator =(Runnable const&) = delete;

    void stop() { m_stop = true; m_thread.join(); }
    void start() { m_thread = std::thread(&Runnable::run, this); }

protected:
    virtual void run() = 0;
    std::atomic<bool> m_stop;

private:
    std::thread m_thread;
};


class myThread : public Runnable
{
protected:
    void run() { while (!m_stop) { /* do something... */ }; }
};

#endif // RUNNABLE_H
Run Code Online (Sandbox Code Playgroud)

一些说明:

  • 像你m_stop一样简单地宣称bool是非常不足够的; 阅读内存障碍
  • std::thread::join可以扔掉所以在没有try..catch析构函数的情况下调用它是鲁莽的
  • std::thread并且std::atomic<>是不可复制的,所以Runnable应该这样标记,如果没有其他原因而不是用VC++避免C4512警告

  • 我不认为`m_stop`变量需要`volatile`,`std :: atomic <bool>`会处理多线程问题,而`volatile`在那里没有额外的帮助. (3认同)
  • -1:`std :: atomic`(lockfree)和`volatile`(硬件)是正交概念.请参阅我的问题[为什么挥发性限定符通过std :: atomic使用?](http://stackoverflow.com/q/2479067/28817),特别是@Herb Sutter的答案.这里不需要易失性,`std :: atomic`的语义足以防止有害的重新排序.答案中的其他所有内容都很好.在我的日常工作中,我正处于对基于"易失性"的并发性的圣战中. (3认同)
  • 我没有注意到之前评论中的拼写错误,但我认为它比新版本更准确.标准在该段中所说的是对原子对象的操作可以*合并*(不说重新排序).我对它的理解是`std :: atomic <int> i = 0; for(; i <10; i = i + 1){}`可以转换为`std :: atomic <int> i = 10;`(这对于`volatile`变量是不可行的,其中所有读写都是最终可执行文件中要求的).尽管如此,我还没有足够的时间来阅读标准的`atomic`部分*(如完全摘要). (2认同)

Dav*_*eas 15

这种做法是错误的.

问题是,当对象仍在构建时,它的类型仍然不是最派生的类型,而是正在执行的构造函数的类型.这意味着当你启动线程时,对象仍然是一个,Runnable并且run()可以调用to Runnable::run(),这是纯虚拟的,这反过来会导致未定义的行为.

更糟糕的是,您可能会遇到虚假的安全感,因为在某些情况下,正在启动的线程可能需要足够长的时间才能使当前线程完成Runnable构造函数,并输入myThread对象,在这种情况下新线程将执行正确的方法,但更改执行程序的系统(不同的核心数,或系统的负载,或任何其他不相关的情况),程序将在生产中崩溃.