在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;
};
它的优点是不使用虚拟函数,所以没有虚表和更少的RAM使用(我正在为MCU开发,而不是PC,所以RAM使用很重要)。它也不需要虚析构函数。
而且我认为这更有意义,因为一个典型的对象更倾向于ha - a线程(组合),而不是IS-A线程(继承),对吧?(;
与继承方法相反,这种设计是否有任何缺陷,因为我没有在任何地方看到它的建议?对于每个实例化,你肯定会得到_trampoline()的副本,但这与继承版本中的虚函数调用没有太大不同……我希望create()和getHandle()是内联的,因为没有理由不…
这解决了" This "地址的问题
#include <pthread.h>
template <class T, void * (T::*thread)()>
class Thread
{
public:
int create(T* passedThis) { return pthread_create(&_handle, nullptr, _trampoline, passedThis); };
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;
};
您的Thread::_trampoline
方法没有extern "C"
链接,因此,尽管这可能在实践中起作用,但这是不正确的。因为你不能给模板函数提供正确的链接,所以没有一种简单的方法来自动化这个,除非你允许使用宏。
而且我认为这更有意义,因为一个典型的对象更倾向于ha - a线程(组合),而不是IS-A线程(继承),对吧?(;
不,这取决于你的模型。
- 活动对象经常紧密地绑定到单个线程(所以你可以考虑一个实例IS-A并发执行进程)
- 与任务队列(或线程池),它经常是任务是对象,而线程是与一些调度逻辑(队列/池本身可能是一个对象,当然,但这似乎不是你的建议)
老实说,如果你创建了这么多不同的顶级线程函数,你担心变量表占用的内存,我怀疑你的设计首先是错误的。
正如Useless在回答中提到的,严格来说,pthread
库调用的线程函数需要是extern "C"
。虽然静态成员函数在几乎所有情况下都有效,但从语言律师的角度和至少一种实际情况来看,它是不正确的。详见https://stackoverflow.com/a/2068048/12711
extern "C"
函数提供pthread
库和你的类模板之间的接口,但它似乎需要一点开销:
#include <pthread.h>
struct trampoline_ctx
{
void* (*trampoline)(void*);
void* obj;
};
extern "C"
void* trampoline_c(void* ctx)
{
struct trampoline_ctx* t = static_cast<struct trampoline_ctx*>(ctx);
return (t->trampoline)(t->obj);
}
template <class T, void * (T::*thread)()>
class Thread
{
public:
int create(T *that) {
ctx.trampoline = _trampoline;
ctx.obj = that;
return pthread_create(&_handle, nullptr, trampoline_c, &ctx);
};
pthread_t getHandle() const { return _handle; };
private:
static void * _trampoline(void *that) { return (static_cast<T *>(that)->*thread)(); };
pthread_t _handle;
struct trampoline_ctx ctx;
};
我同意在大多数情况下,复合而不是继承可能是更好的线程模型。
当然,请记住c++ 11提供了std::thread
,这是一种模板化的非继承设计。如果c++ 11没有选项,请参阅boost::thread
。