C++ 使用成员函数启动线程
我正在尝试构造一个C++ 使用成员函数启动线程,c++,multithreading,c++11,C++,Multithreading,C++11,我正在尝试构造一个std::thread,其中包含一个成员函数,该函数不接受任何参数并返回void。我想不出任何有效的语法——不管发生什么,编译器都会抱怨。实现spawn()以返回执行test()的std::thread的正确方法是什么 #包括 B类{ 无效测试(){ } 公众: std::thread spawn(){ 返回{test}; } }; 更新:我想解释更多的观点,其中一些观点也在评论中讨论过 上述语法是根据调用定义(§20.8.2.1)定义的: 定义调用(f,t1,t2,…,t
std::thread
,其中包含一个成员函数,该函数不接受任何参数并返回void
。我想不出任何有效的语法——不管发生什么,编译器都会抱怨。实现spawn()
以返回执行test()
的std::thread
的正确方法是什么
#包括
B类{
无效测试(){
}
公众:
std::thread spawn(){
返回{test};
}
};
更新:我想解释更多的观点,其中一些观点也在评论中讨论过 上述语法是根据调用定义(§20.8.2.1)定义的: 定义调用(f,t1,t2,…,tN),如下所示:
- (t1.*f)(t2,…,tN)当f是指向类T的成员函数的指针,t1是类型T的对象或对类型T的对象的引用时 类型T或对从T派生的类型的对象的引用李>
- ((*t1)。*f)(t2,…,tN)当f是指向类T的成员函数的指针且t1不是前面描述的类型之一时 项目李>
- t1.*f,当N==1且f是指向类T的成员数据的指针且t1是类型T或a的对象时
对T型对象的引用或对a型对象的引用
由T派生的类型李> - (*t1)。*f,当N==1且f是指向类T的成员数据的指针且t1不是上一项中描述的类型之一时李>
- f(t1,t2,…,tN)在所有其他情况下
我想指出的另一个普遍事实是,默认情况下,线程构造函数将复制传递给它的所有参数。这样做的原因是,参数可能需要比调用线程更长寿,复制参数可以保证这一点。相反,如果您想真正传递引用,可以使用由
std::ref
创建的std::ref\u包装器
std::thread (foo, std::ref(arg1));
通过这样做,您可以保证在线程对参数进行操作时,这些参数仍然存在
请注意,上面提到的所有内容也可以应用于std::async
和std::bind
,因为您使用的是C++11,lambda表达式是一个很好且干净的解决方案
class blub {
void test() {}
public:
std::thread spawn() {
return std::thread( [this] { this->test(); } );
}
};
由于此->
可以省略,因此可以缩短为:
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;
}
一些用户已经给出了答案,并且解释得很好
我想再添加一些与线程相关的内容。
如何使用函子和线程。
请参考下面的例子
线程将在传递对象时创建自己的对象副本
#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()
{
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;
}
改写后的样本将是:
#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;
}
#包括
#包括
类包装器{
公众:
无效成员1(){
std::难道你的意思是函数返回void,称为void,或者它没有任何参数。你能为你正在尝试做的事情添加代码吗?你测试过吗?(我还没有)。你的代码似乎依赖于RVO(返回值优化),但我认为你不应该这样做。我认为使用std::move(std::thread(func))
更好,因为std::thread
没有复制构造函数。@RnMss:,在这种情况下使用std::move
是多余的-如果不是这样,并且没有复制构造函数,编译器无论如何都会给出一个错误。至少以这种方式编译。尽管我不知道为什么要将实例作为第二个参数传递nt@LCID:std::thread
构造函数的多参数版本的工作原理就像参数被传递给std::bind
一样。要调用成员函数,std::bind
的第一个参数必须是指向适当类型的对象的指针、引用或共享指针。该构造函数从何处获取r的行为就像一个隐式的bind
?我在任何地方都找不到。@KerrekSB,比较[thread.thread.constr]p4和[func.bind.bind]p3,语义非常相似,是根据调用伪代码定义的,调用伪代码定义了如何调用成员函数,而不是作为类实例的第一个参数的静态成员函数(程序员看不到),因此当将此方法作为原始函数传递时,在编译和声明不匹配的过程中总会遇到问题。通常,在按值返回局部变量时,不应使用std::move
。这实际上会抑制RVO。如果只按值返回(不移动)编译器可能使用RVO,如果不使用,则标准要求它必须调用移动语义。@zmb,除了您希望在VC10上编译代码外,如果返回类型不可复制,则必须移动。RVO仍然生成比移动语义更好的代码,并且不会消失。小心使用[=]
。这样你就可以不经意地复制一个巨大的对象。一般来说,使用[&]
或[=]
@每个人都不要忘记这里是一个线程。这意味着lambda函数可能会超出其上下文范围。因此通过使用引用捕获([&]
),你可能会引入一些错误,比如一些悬空引用。(例如,std::thread spawn(){int i=10;返回std::thread([&]{std::coutn与OP问题并不相关,但为什么要在堆上分配包装器(而不是取消分配它)?您有java/c#后台吗?别忘了从堆中删除内存:)没有理由在程序结束前删除对象。不要无缘无故地让人感到羞愧。
#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();
}
#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;
}