【发布时间】:2013-01-18 12:36:40
【问题描述】:
在 C++ 中将 pthread 与类的成员函数一起使用的“典型”方法是使用继承(如此处建议的 https://stackoverflow.com/a/1151615/157344 )。但为什么不这样呢:
#include <pthread.h>
template <class T, void * (T::*thread)()>
class Thread
{
public:
int create(T *that) { return pthread_create(&_handle, nullptr, _trampoline, that); };
pthread_t getHandle() const { return _handle; };
private:
static void * _trampoline(void *that) { return (static_cast<T *>(that)->*thread)(); };
pthread_t _handle;
};
可以这样使用:
class SomeClassWithThread
{
public:
int initialize() { return _thread.create(this); };
private:
void * _threadFunction();
Thread<SomeClassWithThread, &SomeClassWithThread::_threadFunction> _thread;
};
它的优点是不使用虚拟功能,因此不使用 vtable 并且使用的 RAM 更少(我正在为 MCU 开发它,而不是为 PC 开发,因此 RAM 的使用很重要)。它也不需要虚拟析构函数。
此外,我认为它更有意义,因为典型的对象而不是 HAS-A 线程(组合),而不是 IS-A 线程(继承),对吧? (;
与继承方法相比,这种设计是否有任何缺陷,因为我在任何地方都没有看到它提出的建议?您肯定会为每个实例化获取 _trampoline() 的副本,但这与继承版本中的虚函数调用没有太大区别......我希望 create() 和 getHandle() 将被内联,因为没有理由不...
【问题讨论】:
-
根据我的经验,您链接到的问题的公认答案比基于继承的版本更典型。
-
@molbdnilo - 当然,但这不是一种“通用”或“自动”的方式来做到这一点 - 它只是为你想用 pthread 增强的每个类手动提供这样的 trampoline() .无论如何,我认为我的模板方法更接近于这样的版本——它只是一个非常漂亮的宏,可以做同样的事情(;或者至少我认为确实如此——我是这些领域的新手......
-
您可能希望向 Thread 类添加一个析构函数,以便在该类被销毁时停止线程。 Nitpick:在变量名中使用前导下划线是个坏主意;这些是为编译器保留的。
-
我认为这里有一个错误:您在 create() 中使用的“this”是帮助程序类的地址,而不是您要用作客户端的类的地址。你的例子是偶然的,因为你的助手类是第一个成员。
-
@SimonElliott,这些名称不是保留的。
_This是保留名称,__this也是,但_this不在全局命名空间中(并且这些名称都不在全局命名空间中)
标签: c++ multithreading templates pthreads