我可以给你两种回答:一种是展示在C++中如何正确地实现你想做的事情(启动一个线程),另一种是展示如何将
std::function
对象压缩进
pthread_create
。前者更加实用,而后者则能够解释
pthread_create
如何处理上下文。两种方法都有价值,因此:
1. 如何在新线程中调用std::function<void*()>
对象
自从C++11以来,标准库就包含了多线程功能。在你的情况下,我们有一个带返回值的函数,所以任务就是:
- 异步调用该函数,
- 在需要时获取返回值。
最简单的方法是使用std::async
和std::future<void*>
。考虑以下简单示例来进行一个异步调用:
std::function<void*()> f;
std::future<void*> fut = std::async(std::launch::async, f);
void *value_returned_by_f = fut.get();
在您的情况下,您想调用多个函数并在方便时获取返回值,因此您希望将
std::future<void*>
对象存储在某个地方。幸运的是,您的代码结构可以大部分保留:
vector<function<void*()>> signals;
vector<std::future<void*>> signal_futures;
void MasterSignalHandler()
{
for (auto & signal_handler : signals)
{
signal_futures.push_back(std::async(std::launch::async, signal_handler));
}
}
您可以随时从 signal_futures
中检索返回值。
请注意,如果这些函数不返回值,则可以使用 std::thread
替代 std::future
:
vector<function<void()>> signals;
vector<std::thread> signal_threads;
void MasterSignalHandler()
{
for (auto & signal_handler : signals)
{
signal_threads.emplace_back(signal_handler);
}
}
不要使用.get()
从future中获取结果,而是最终使用.join()
线程。使用std::future<void>
也可以,所以这主要取决于个人口味。
2. 如何将std::function<void*()>
强制转换为pthread_create
我们刚刚提到了解决问题的明智方法,现在让我们看看更棘手的部分。您的原始代码无法编译的原因是,pthread_create
期望一个指向函数(即机器码)的内存地址,它可以执行,而signal_handler
不是这样的内存地址,而是一个带有状态的复杂对象。pthread_create
无法处理它。
然而:如果您仔细观察,您会注意到pthread_create
所需的函数带有void*
参数,并且pthread_create
稍后在其签名中使用void *
参数 - 当启动线程时,此后者参数将传递给函数。如果我们真的想这么做,在基于POSIX的系统上,std::thread
通常会完全为您执行此操作。例如:
void *thread_stub(void *context) {
std::function<void*()> &func = *static_cast<std::function<void*()>*>(context);
return func();
}
std::function<void*()> f;
pthread_t thread_handle;
pthread_create(&thread_handle, NULL, thread_stub, &f);
请注意,我不建议以这种方式进行操作。它很丑陋,并且存在上面评论中提到的问题。 std :: thread
及其在标准库中关联的类为您解决了所有这些问题,因此没有必要重新发明这个特定的轮子。
std::thread
吗? - Fred Larsonstd::function
不是pthread_create
支持的参数。但是它可以被std::thread
接受,并且在 POSIX 环境之外也可以工作。 - Drew Dormann