子类化std :: thread并转发打包/ variadic模板参数

时间:2016-03-10 09:05:33

标签: c++ templates subclass variadic stdthread

在我的代码中,我希望所有的线程都是从一个类型继承子类,而这个类型又来自std :: thread的子类。原因,我确信很常见:

  1. 来自线程外部的停止请求,并从线程内部继续检查,无论它是哪种类型的线程,都以相同的方式完成。换句话说,每种类型的线程都没有自己的停止/检查逻辑。
  2. 在线程中运行的代码不必关心它是否实际在线程中运行,而不是调用thread::shouldBeRunning(),如果不在线程内,则始终返回true
  3. 然而,(我认为)我是如何将std::thread的子类中的模板参数/值传递给包装函数的问题,在下面的代码中{{1 }}

    static void run(thread * This, Function&& Func, Args&&... a)

    MSVC 2013吐出一条长错误链,其中最重要的是:

        #include <thread>
        #include <atomic>
        #include <iostream>
    
        class thread
        {
            friend int main(int, char **);
    
        private:
            std::atomic<bool> m_ShouldBeRunning;
            std::atomic<bool> m_Running;
            int               m_Error;
            std::thread       m_Thread;
    
        #ifdef WIN32
            __declspec(thread) static thread * m_Local;
        #else
            __thread static thread * m_Local;
        #endif
    
            template <typename Function, typename... Args>
            static void run(thread * This, Function&& Func, Args&&... a)
            {
                thread::m_Local = This;
    
                try
                {
                    std::bind(std::forward<Function>(Func), std::forward<Args>(a)...)();
                }
                catch (int Error)
                {
                    This->m_Error = Error;
                }
                This->m_Running.store(false, std::memory_order_release);
            }
    
        public:
    
            template <typename Function, typename... Args>
            thread(Function&& Func, Args&&... a)
                : m_ShouldBeRunning(true)
                , m_Running(true)
                , m_Error(0)
                , m_Thread(&thread::run<Function, Args...>,
                            this,
                            std::forward<Function>(Func),
                            std::forward<Args>(a)...)
            {}
            virtual ~thread()
            {
                try
                {
                    stop();
                    m_Thread.join();
                }
                catch (...)
                {
                    std::cerr << "caught exception in ~thread!";
                }
            }
    
            bool isRunning() const { return m_Running.load(std::memory_order_acquire); }
    
            static thread * get() { return thread::m_Local; }
    
            static bool shouldBeRunning()
            {
                thread * Thread = thread::m_Local;
                return (Thread)
                    ? Thread->m_ShouldBeRunning.load(std::memory_order_acquire)
                    : true;
            }
    
            void stop() { m_ShouldBeRunning.store(false, std::memory_order_release); }
        };
    
        thread * thread::m_Local = NULL;
    
        class doStuff
        {
        private:
            int   m_X;
            float m_Y;
            char  m_Z;
    
        public:
            doStuff(int X, float Y, char Z)
                : m_X(X), m_Y(Y), m_Z(Z) {}
    
            void stuff(int X, float Y, char Z)
            {
                while (thread::shouldBeRunning())
                {
                    std::cout << (X + m_X) << " " << (Y + m_Y) << " " << Z << m_Z << std::endl;
                    std::this_thread::sleep_for(std::chrono::seconds(1));
                }
            }
        };
    
        class threadDoStuff : public thread
        {
        public:
            threadDoStuff(doStuff & Stuff, int X, float Y, char Z)
                : thread(&doStuff::stuff,
                             &Stuff,
                             X,
                             Y,
                             Z)
            {}
        };
    
        int main(int argc, char ** argv)
        {
            doStuff stuff(3, 2.0f, 'z');
            threadDoStuff stuffThread(stuff, 5, 1.0f, 'a');
    
            std::this_thread::sleep_for(std::chrono::seconds(30));
    
            return 0;
        }
    

1 个答案:

答案 0 :(得分:0)

感谢Jarod42和Piotr提供部分解决方案,但我的问题最终通过升级到MSVC 2015来解决。根据some comments,早期版本的MSVC存在处理std::thread构造函数参数的问题。虽然我无论如何都会进行升级,但我想在没有升级的情况下找出问题,但这需要花费太多时间。我还没有运行代码,但至少它会编译。

TLDR - 我没有弄清楚原因,但可能是由于MSVC,因为升级修复了它。