我有以下类:
class Foo {
private:
Bar *_bar;
void *run(void *);
public:
Foo(Bar *bar);
}
我想Foo::Foo
启动一个运行Foo::run
的线程。
我知道这可以使用std::thread
来完成:
Foo::Foo(Bar *bar) : _bar(bar) {
_thread = std::thread(&Foo::run, this);
}
问题是我需要为此线程设置优先级和调度策略 - 这可以使用pthread
来实现。
(非常)可悲的是,我无法更改系统的设计,我必须在 C'tor 内部生成线程。
pthread
是一个 C API,我不知道如何在非静态成员函数上运行它。以下尝试未编译:
Foo::Foo*(Bar *bar) : _bar(bar) {
// attempt 1
pthread_create(&thread, NULL, &Foo::run, this);
// attempt 2
pthread_create(&thread, NULL, (void* (*)(void *))(&Foo::run), this);
}
从pthread_create
手册页 - 第三个参数(start_routine
)是一个指针,指向返回void *
和接收void *
的函数。
C 和 C++ 的调用约定完全不同,因为 C++ 函数(除非是静态的)需要知道使用类的哪个实例调用其成员函数。
你可以做的是有一个静态函数,传入的参数是实例指针。喜欢这个:
class Foo
{
private:
Bar *_bar;
static void *start_thread(void *ptr) { return dynamic_cast<MyThread *>(ptr)->run(); }
void *run(); // Implement thread here.
public:
Foo(Bar *bar);
}
Foo::Foo(Bar *bar) : _bar(bar) {
pthread_create(&thread, NULL, Foo::start_thread, this);
}
成员函数不像自由函数。它们需要类的实例才能调用。因此,类型系统以不同的方式对待它们,指向成员函数的指针不像指向自由函数的常规指针。std::thread
使用模板来提供可以接受任一的便捷 API。
当然,pthreads 不是模板化的,并且不考虑任何不是自由函数的东西。要使其在对象上运行成员函数,您需要一个蹦床函数。一个函数,可以衰减为自由函数指针,并包含用于在作为 void 传递的实例上执行成员的代码。
如果您发现自己经常需要这些,您可以编写一个模板来为您生成它们。这样:
template<class C, void* (C::* run_mem)()> // Member function without argumnets
void* pthread_member_wrapper(void* data) {
C* obj = static_cast<C*>(data)
return (obj->*run_mem)();
}
因此,如果您将run
定义为void *run();
,则可以在任何可以访问run
的地方使用上面的包装器:
Foo::Foo*(Bar *bar) : _bar(bar) {
pthread_create(&thread, NULL,
pthread_member_wrapper<Foo, &Foo::run>,
this);
}
由于pthread_member_wrapper
是在类和成员函数指针上模板化的,因此可以在可访问该成员的任何范围内与任何类重用它。它不必是Foo
本身的成员。