pthread for a member function of class in C++ - why not template?
使用C++中具有类成员函数的p螺纹的一种"典型"方法是使用继承(如这里建议的HTTPS://StaskOfFult.COM/A/1151615/157334)。但是为什么不这样呢:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #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; }; |
可以这样使用:
1 2 3 4 5 6 7 8 9 | class SomeClassWithThread { public: int initialize() { return _thread.create(this); }; private: void * _threadFunction(); Thread<SomeClassWithThread, &SomeClassWithThread::_threadFunction> _thread; }; |
它的优点是不使用虚拟功能,因此不使用vtable,使用的RAM更少(我正在为一个MCU开发,而不是为一台PC开发,因此RAM的使用很重要)。它也不需要虚拟析构函数。
此外,我认为这更有意义,因为一个典型的对象有线程(组合),而不是线程(继承),对吗?(;
与继承方法相比,我在任何地方都没有看到这种设计有什么缺陷吗?对于每个实例,您都会得到一个Trampoline()的副本,但这与继承版本中的虚拟函数调用没有太大的区别…我希望create()和gethandle()是内联的,因为没有理由不…
正如他回答中提到的无用,严格地说,
但是,您可以让一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #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提供了EDCOX1,6,这是一个模板化的非继承性设计。并看EDCOX1 7,如果C++ 11不是一个选项。
您的
Moreover I think it makes more sense, because a typical object rather HAS-A thread (composition), than IS-A thread (inheritance), right? (;
不,这取决于你的型号。
- 活动对象经常紧密地绑定到单个线程(因此,您可以考虑将实例与同时执行的进程进行比较)。
- 对于任务队列(或线程池),任务通常是对象,而线程与某些调度逻辑相关联(当然,队列/池本身也可能是对象,但这似乎不是您建议的那样)
老实说,如果您创建了这么多不同的顶级线程函数,以至于担心vtables占用的内存,那么首先我怀疑您的设计是错误的。
这解决了"this"地址的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #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; }; |
更新用法:
1 2 3 4 5 6 7 8 9 | class SomeClassWithThread { public: int initialize() { return _thread.create(this); }; private: void * _threadFunction(); Thread<SomeClassWithThread, &SomeClassWithThread::_threadFunction> _thread; }; |