【问题标题】:std::thread, start thread on `this' (from within the class itself)std::thread,在“this”上启动线程(从类本身)
【发布时间】:2012-02-29 16:35:52
【问题描述】:

我正在尝试创建一个启动其成员方法之一的线程实例的类。 当我做主时:

test myinstance;
std::thread mythread(myinstance);

然后事情编译。但使用以下构造:

#include <stdio.h>
#include <unistd.h>
#include <thread>

class test
{
        std::thread *pt;
public:
        test()
        {
                pt = new std::thread(this);
        }

        void operator()() const
        {
                printf("thread start\n");
                sleep(5);
                printf("thread end\n");
        }
};

int main(int arg, char *argv[])
{
        test ptest;
        sleep(10);

        return 0;
}

我收到以下错误:

folkert@here:~$ g++ -std=c++0x test.cpp 在包含的文件中 /usr/include/c++/4.6/thread:39:0, 来自 test.cpp:3: /usr/include/c++/4.6/functional: 在成员函数 'void std::_Bind_result<_result _functor ...>::__call(std::tuple<_args ...>&&, std::_Index_tuple<_indexes ...>,类型名 std::_Bind_result<_result ...>::__enable_if_void<_res>::type) [with _Res = void, _Args = {}, int ..._Indexes = {},_Result = void,_Functor = test*,_Bound_args = {},类型名 std::_Bind_result<_result _functor ...>::__enable_if_void<_res>::type = int]': /usr/include/c++/4.6/functional:1378:24: 实例化自 'std::_Bind_result<_result _functor ...>::result_type std::_Bind_result<_result _functor ...>::operator()(_Args&& ...) [with _Args = {}, _Result = void, _Functor = test*, _Bound_args = {}, std::_Bind_result<_result _functor ...>::result_type = void]' /usr/include/c++/4.6/thread:117:13: 从 ' 实例化空白 std::thread::_Impl<_callable>::_M_run() [with _Callable = std::_Bind_result]' test.cpp:28:1: 实例化自 这里 /usr/include/c++/4.6/functional:1287:4: 错误: '((std::_Bind_result*)this)->std::_Bind_result::_M_f' 不能作为函数使用

所以我的猜测是它不会这样工作。 我现在的问题是:我怎样才能使用 std::thread 让一个类启动它自己的方法之一的线程?

【问题讨论】:

    标签: c++ multithreading


    【解决方案1】:

    std::threads 的一个构造函数如下所示:

    template<typename Callable>
        explicit thread(Callable func);
    

    这要求你传递可调用的东西,这意味着它可以用operator() 调用。您传递给 std::thread 的内容不可调用。

    你不能打电话给thisthis是指向当前对象的指针,不可调用。

    您需要将成员函数或其他函数传递给您的 std::thread 构造函数。

    您还可以创建一个仿函数并传递它,因为它是可调用的。

    编辑:刚刚注意到确实重载了operator(),要调用它,您必须执行以下操作:

      test t;
      std::thread my_thread(t); //invokes operator() on test.
    
    //also remove this statement from your ctor:  pt = new std::thread(this);
    

    【讨论】:

    • 啊,是的,Joachim Pileborg 给出了答案!如果我这样做 pt = new std::thread(*this);甚至 pt = new std::thread(std::ref(*this));然后它编译并运行!
    • @FolkertvanHeusden 我必须说,当您使用同一类的重载 operator() 时,您在类的 ctor 中启动线程的构造很奇怪。
    • 这似乎是在尝试模拟 Java 的(损坏的)线程 API。正如@Tony 所说,将您的可调用对象 传递给 线程构造函数。不要将线程放在它应该调用的对象中。
    • @jalf 这样做的想法是,我不希望我班级的用户知道它是如何做的。如果是例如在调用时或在后台检索远程数据。事实上,我可能有点受 java 影响:-)
    • 然后把它分成两个类。一个包含thread 对象,另一个传递给要执行的线程。两者是完全不同的关注领域,不应该在同一个班级。
    【解决方案2】:

    许多修复:

    #include <iostream>
    #include <thread>
    
    struct test
    {
        void operator()() const
        {
            std::cout << "thread start\n";
            sleep(5);
            std::cout << "thread end\n";
        }
    };
    
    int main(int arg, char *argv[])
    {
        std::thread pt(std::move(test()));
    
        pt.join();
        return 0;
    }
    

    修复

    • 关注点分离(你现在可以在没有线程的情况下运行test,耶!)
    • 泄露 std::thread 实例(内存 + 资源)
    • 不(确定地)等待线程完成;这就是 UB,即使你认为你知道睡眠会持续更长时间
    • 注意如何通过移动来避免 ptest 的本地/副本。 从技术上讲,std::move 在那里是多余的,但我喜欢具体的东西,你会遇到most vexing parse

      std::thread pt((test()));
      

    【讨论】:

    • 关于没有线程的测试:我可以向构造函数添加一个参数,例如不启动线程的 bool debug,然后手动调用 worker-part(通常在线程中) .这样就可以保持信息隐藏。
    • @FolkertvanHeusden 从什么时候开始执行模型信息?如果该类是 TaskManager 或其他东西,则可能是这样。现在,从逻辑上讲,函子没有责任决定它在哪里执行,线程也没有责任决定调用什么功能......?在我看来,这不是信息隐藏,而是混杂的信息共享
    • 我隐藏了检索方式和时间等信息。好吧,也许“信息隐藏”不是它的正确名称,但我想要实现的是一个黑盒,它以某种方式检索某些东西,而不向外界展示事情是如何完成的。
    【解决方案3】:

    试试这个。

    pt = new std::thread(std::ref(*this));

    【讨论】:

    • 糟糕,抱歉看到我的回答重复了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-02
    • 2014-08-06
    • 2012-04-24
    • 1970-01-01
    • 2021-04-07
    相关资源
    最近更新 更多