我正在尝试使用不带参数的成员函数构造std::thread
并返回void
。我无法弄清楚任何有效的语法 - 编译器无论如何都会抱怨。实施spawn()
的正确方法是什么,以便它返回执行std::thread
的{{1}}?
test()
答案 0 :(得分:313)
#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();
}
编辑: 考虑编辑,您必须这样做:
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的成员数据的指针时,t 1是类型为T或者对象的对象 引用类型为T的对象或引用对象的对象 类型派生自T;
- (* t1)。* f当N == 1且f是指向T类成员数据的指针时,t 1不是前一项中描述的类型之一;
- f(t1,t2,...,tN)在所有其他情况下。
我想指出的另一个一般事实是,默认情况下,线程构造函数将复制传递给它的所有参数。原因是参数可能需要比调用线程更长,复制参数保证了这一点。相反,如果您想真正传递引用,可以使用由std::reference_wrapper
创建的std::ref
。
std::thread (foo, std::ref(arg1));
通过这样做,您承诺在线程对它们进行操作时,您将保证参数仍然存在。
请注意,上述所有内容也可以应用于std::async
和std::bind
。
答案 1 :(得分:84)
由于您使用的是C ++ 11,因此lambda-expression是一个不错的&amp; clean解决方案。
class blub {
void test() {}
public:
std::thread spawn() {
return std::thread( [this] { this->test(); } );
}
};
因为this->
可以省略,所以可以缩短为:
std::thread( [this] { test(); } )
或只是
std::thread( [=] { test(); } )
答案 2 :(得分:27)
这是一个完整的例子
#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)
答案 3 :(得分:13)
@ 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
来自this answer的重写样本将是:
#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;
}
答案 4 :(得分:0)
有些用户已经给出了答案,并对其进行了很好的解释。
我想补充一些与线程相关的内容。
如何使用仿函数和线程。 请参考以下示例。
线程将在传递对象时创建自己的对象副本。
#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();
}
实现同样目标的另一种方式是:
void main()
{
thread t((CB()));
t.join();
}
但是如果你想通过引用传递对象,那么使用以下语法:
void main()
{
CB obj;
//thread t(obj);
thread t(std::ref(obj));
t.join();
}