创建非静态成员函数的 pthread

Creating a pthread of nonstatic member function

本文关键字:pthread 函数 静态成员 创建      更新时间:2023-10-16

我有以下类:

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本身的成员。