在 C++ 中运行类成员函数的线程
Posted
技术标签:
【中文标题】在 C++ 中运行类成员函数的线程【英文标题】:run threads of class member function in c++ 【发布时间】:2011-01-12 08:27:07 【问题描述】:正如标题所说。 以下是我的代码骨架。
class CLASS
public:
void A();
private:
DWORD WINAPI B(LPVOID);
;
void CLASS::A()
DWORD (WINAPI CLASS::*thread)(LPVOID) = &CLASS::B;
...
CreateThread(NULL, 0, thread, &arg, 0, NULL);
...
函数B需要CLASS的成员变量。 但是当我编译这个时,我得到了一个错误代码。 它是“无法将参数 3 从 'DWORD (__stdcall CLASS::* )(LPVOID)' 转换为 'LPTHREAD_START_ROUTINE'”或类似的东西。 不知道英文环境是不是也一样。
有人可以帮忙吗?
【问题讨论】:
【参考方案1】:说真的,使用std::thread
:
class CLASS
public:
void A();
private:
void B(your args go here);
;
void CLASS::A()
std::thread t(&CLASS::B, this, your args go here);
// when done
t.join();
// or
t.detach();
说明
您的代码无法编译,因为CreateThread
是一个 C API,需要一个非成员 C 函数作为回调。为了调用 C++ 类的非静态成员函数,调用者需要了解this
指针以及如何正确使用它。由于 WinAPI 显然没有 this
并且不期望成员函数指针,因此这不可能工作。您的编译器会捕捉到这一点并将其报告为类型不匹配错误。
这就是CreateThread
的lpParameter
发挥作用的地方。它允许您通过该参数传递this
。然而它并没有改变CreateThread
不知道如何调用C++ 成员函数的事实。因此,您有责任将其包装在一个静态函数中,该函数将执行成员函数调用:
class CLASS
public:
void A();
private:
DWORD B();
static DWORD s_B(LPVOID);
;
DWORD CLASS::s_B(LPVOID that)
return ((CLASS*)that)->B();
void CLASS::A()
CreateThread(NULL, 0, s_B, this, 0, NULL);
这就是@Nawaz 在他们的回答中所做的,除了稍微更笼统的方式。
尽管这种方法有效,但它显然也有缺点:
很冗长。 它不便携。 您需要通过不同的方式(例如通过您的班级成员)传递您原来的args
。
std::thread
已经为您完成了所有这些工作。
【讨论】:
+1。是的,绝对要使用 std::/boost::thread。此外,您甚至不需要绑定:boost::thread t(&CLASS::B, this, your args if any go here);
。就这么简单。【参考方案2】:
如果它是成员函数,您必须将回调函数定义为 static
函数!
更好的设计:定义一个可重用的类!
来自我的previous answer:(稍作修改)
更好的办法是定义一个 可重用 类,该类具有纯虚函数 run()
以由派生的 thread 类实现。以下是它的设计方式:
//runnable is reusable class. All thread classes must derive from it!
class runnable
public:
virtual ~runnable()
static DWORD WINAPI run_thread(LPVOID args)
runnable *prunnable = static_cast<runnable*>(args);
return prunnable->run();
protected:
virtual DWORD run() = 0; //derived class must implement this!
;
class Thread : public runnable //derived from runnable!
public:
void newthread()
CreateThread(NULL, 0, &runnable::run_thread, this, 0, NULL);
protected:
DWORD run() //implementing the virtual function!
/*.....your thread execution code.....*/
【讨论】:
我会使用模板,而不是运行时继承。但总体思路是正确的。 @DeadMG : 是的..那会有点快...只是我写这篇文章的时候没想到... @Nawaz:您应该始终首先考虑 CRTP,然后再考虑运行时继承。 @DeadMG:是的。我现在意识到了。 :-) 必须派生一个类并重写一个函数来运行线程,这有点过时和尴尬的设计。最好使用 boost::thread 或接受函子作为线程函数并且不需要派生任何东西的类似机制。【参考方案3】:你必须使那个成员函数static
。
这里的问题是每个非静态成员函数都有一个隐含的this
参数,这实际上是编译器试图告诉你的——你的非静态成员函数的签名与你预期的不同。
另见this answer to a closely related question。
【讨论】:
在 OP 开始获得任何聪明的想法之前 - 非静态类成员函数指针是奇怪的。不仅调用约定与简单的func(classname *this, ...)
不同,指针表示 也很奇怪——在某些情况下,类成员函数指针最终可能是普通函数指针大小的 2 倍,所以不要甚至没有考虑强迫演员:)以上是关于在 C++ 中运行类成员函数的线程的主要内容,如果未能解决你的问题,请参考以下文章
使用std::future监控线程执行类成员函数(c++)? [复制]
如何在一个类中执行 C++ 多线程(将线程引用保持为成员 var)