用成员函数启动线程

我试图构造一个std::thread成员函数,不接受参数并返回void。我想不出任何可行的语法——无论如何编译器都会抱怨。实现spawn()以返回执行test()std::thread的正确方法是什么?

#include <thread>
class blub {
void test() {
}
public:
std::thread spawn() {
return { test };
}
};
439372 次浏览
#include <thread>
#include <iostream>


class bar {
public:
void foo() {
std::cout << "hello from member function" << std::endl;
}
};


int main()
{
std::thread t(&bar::foo, bar());
t.join();
}
< p >编辑: 计算你的编辑,你必须这样做:

  std::thread spawn() {
return std::thread(&blub::test, this);
}

更新:我想解释更多的观点,其中一些也在评论中讨论过。

上面描述的语法是根据INVOKE定义(§20.8.2.1)定义的:

定义INVOKE (f, t1, t2,…, tN)如下:

    <李> (t1。* f) (t2,…, tN)时,f是指向类T的成员函数的指针,而t1是类型T的对象或对象的引用 类型T或对T派生类型的对象的引用; <李> ((* t1)。* f) (t2,…, tN),当f是指向类T的成员函数的指针,而t1不是前面描述的类型之一时 李物品;< / > <李> t1。*f,当N == 1, f是指向类T成员数据的指针,t1是类型T的对象或a
    对类型为T的对象的引用或对
    的对象的引用 类型派生自T;
  • (* t1)。*f,当N == 1, f是一个指向类T的成员数据的指针,而t1不是前一项中描述的类型之一;
  • F (t1, t2,…在所有其他情况下。

我想指出的另一个普遍事实是,默认情况下线程构造函数将复制传递给它的所有参数。这样做的原因是实参可能需要比调用线程活得更久,复制实参可以保证这一点。相反,如果你真的想传递一个引用,你可以使用std::ref创建的std::reference_wrapper

std::thread (foo, std::ref(arg1));

通过这样做,您承诺在线程对参数进行操作时,您将注意保证参数仍然存在。


请注意,上面提到的所有内容也可以应用于std::asyncstd::bind

因为你使用的是c++ 11, lambda-expression是一个很好的解决方案。

class blub {
void test() {}
public:
std::thread spawn() {
return std::thread( [this] { this->test(); } );
}
};

因为this->可以省略,所以它可以缩短为:

std::thread( [this] { test(); } )

或者只是(弃用)

std::thread( [=] { test(); } )

这是一个完整的例子

#include <thread>
#include <iostream>


class Wrapper {
public:
void member1() {
std::cout << "i am member1" << std::endl;
}
void member2(const char *arg1, unsigned arg2) {
std::cout << "i am member2 and my first arg is (" << arg1 << ") and second arg is (" << arg2 << ")" << std::endl;
}
std::thread member1Thread() {
return std::thread([=] { member1(); });
}
std::thread member2Thread(const char *arg1, unsigned arg2) {
return std::thread([=] { member2(arg1, arg2); });
}
};
int main(int argc, char **argv) {
Wrapper *w = new Wrapper();
std::thread tw1 = w->member1Thread();
std::thread tw2 = w->member2Thread("hello", 100);
tw1.join();
tw2.join();
return 0;
}

使用g++编译会产生以下结果

g++ -Wall -std=c++11 hello.cc -o hello -pthread


i am member1
i am member2 and my first arg is (hello) and second arg is (100)

一些用户已经给出了他们的答案,并且解释得很好。

我想补充一些与线程相关的东西。

  1. 如何使用函子和线程。

  2. 线程在传递对象时将创建自己的对象副本。

    #include<thread>
    #include<Windows.h>
    #include<iostream>
    
    
    using namespace std;
    
    
    class CB
    {
    
    
    public:
    CB()
    {
    cout << "this=" << this << endl;
    }
    void operator()();
    };
    
    
    void CB::operator()()
    {
    cout << "this=" << this << endl;
    for (int i = 0; i < 5; i++)
    {
    cout << "CB()=" << i << endl;
    Sleep(1000);
    }
    }
    
    
    void main()
    {
    CB obj;     // please note the address of obj.
    
    
    thread t(obj); // here obj will be passed by value
    //i.e. thread will make it own local copy of it.
    // we can confirm it by matching the address of
    //object printed in the constructor
    // and address of the obj printed in the function
    
    
    t.join();
    }
    

Another way of achieving the same thing is like:

void main()
{
thread t((CB()));


t.join();
}

但是如果你想通过引用传递对象,那么使用下面的语法:

void main()
{
CB obj;
//thread t(obj);
thread t(std::ref(obj));
t.join();
}

@hop5和@RnMss建议使用c++ 11的lambdas,但如果你处理指针,你可以直接使用它们:

#include <thread>
#include <iostream>


class CFoo {
public:
int m_i = 0;
void bar() {
++m_i;
}
};


int main() {
CFoo foo;
std::thread t1(&CFoo::bar, &foo);
t1.join();
std::thread t2(&CFoo::bar, &foo);
t2.join();
std::cout << foo.m_i << std::endl;
return 0;
}

输出

2

这个答案重写的样本将是:

#include <thread>
#include <iostream>


class Wrapper {
public:
void member1() {
std::cout << "i am member1" << std::endl;
}
void member2(const char *arg1, unsigned arg2) {
std::cout << "i am member2 and my first arg is (" << arg1 << ") and second arg is (" << arg2 << ")" << std::endl;
}
std::thread member1Thread() {
return std::thread(&Wrapper::member1, this);
}
std::thread member2Thread(const char *arg1, unsigned arg2) {
return std::thread(&Wrapper::member2, this, arg1, arg2);
}
};


int main() {
Wrapper *w = new Wrapper();
std::thread tw1 = w->member1Thread();
tw1.join();
std::thread tw2 = w->member2Thread("hello", 100);
tw2.join();
return 0;
}