我是使用<functional>图书馆的新手,所以请耐心等待。以下代码无法编译,并出现此错误:
错误:无法转换
std::function<void*()>到void* (*)(void*)的论点3来int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)。
我不必<functional>在我的代码中使用,但我想在放弃和使用标准函数指针之前,我会看看是否有解决方案。
这是我所拥有的:
vector< function< void*() > > signals;
vector< pthread_t > signal_threads;
// Master Signal Handler
void MasterSignalHandler()
{
for (auto & signal_handler : signals)
{
// Create a thread handle
pthread_t thread_handle;
// Spawn a thread for the signal handler
if (0 == pthread_create(&thread_handle, NULL, signal_handler, NULL))
{
// Push back the thread handle to the signal thread vector
signal_threads.push_back(thread_handle);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想我可以给出两种答案:我可以向您展示在 C++ 中执行您正在尝试执行的操作(启动线程)的正确方法,或者我可以向您展示如何将std::function对象挤入pthread_create. 第一个具有更多的实用价值,而第二个用于解释如何pthread_create处理上下文。两者都有价值,所以:
std::function<void*()>在新线程中调用对象从 C++11 开始,标准库包含用于多线程的工具。在你的情况下,我们有一个带有返回值的函数,所以任务是
最直接的方法是使用std::asyncand std::future<void*>。考虑一个简单的例子,使一个调用以异步方式:
std::function<void*()> f; // the function to call
// Call f asynchronously. It is possible to omit the std::launch::async
// parameter, in which case it is up to the implementation when or even
// if a thread is spawned to make the call.
// The future object represents a handle to the void* value that f will
// eventually return (i.e., the future value).
std::future<void*> fut = std::async(std::launch::async, f);
// Do some other stuff while we're waiting
// get f's return value. This will wait if the thread is not yet finished.
void *value_returned_by_f = fut.get();
Run Code Online (Sandbox Code Playgroud)
在您的情况下,您希望调用多个函数并在空闲时获取返回值,因此您希望将std::future<void*>对象存储在某处。幸运的是,您的代码结构大部分可以保留:
vector<function<void*()>> signals;
vector<std::future<void*>> signal_futures;
// Master Signal Handler
void MasterSignalHandler()
{
for (auto & signal_handler : signals)
{
signal_futures.push_back(std::async(std::launch::async, signal_handler));
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以signal_futures在闲暇时检索返回值。
请注意,如果函数没有返回值,您可以使用std::thread代替std::future:
vector<function<void()>> signals;
vector<std::thread> signal_threads;
// Master Signal Handler
void MasterSignalHandler()
{
for (auto & signal_handler : signals)
{
signal_threads.emplace_back(signal_handler);
}
}
Run Code Online (Sandbox Code Playgroud)
而不是.get()ing 来自未来的结果,你最终会.join()得到线程。使用std::future<void>也可以,所以这主要是品味问题,真的。
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) {
// context is static_cast<void*>(&f) below. We reverse the cast to
// void* and call the std::function object.
std::function<void*()> &func = *static_cast<std::function<void*()>*>(context);
return func();
}
// ...
std::function<void*()> f;
// IMPORTANT: Used this way, f must not go out of scope while the thread
// is running because the thread holds a pointer to it!
pthread_t thread_handle;
pthread_create(&thread_handle, NULL, thread_stub, &f);
Run Code Online (Sandbox Code Playgroud)
请注意,我不建议这样做。它很丑陋,它有上面评论中提到的问题。std::thread及其在标准库中的相关类为您解决了所有这些问题,因此无需重新发明这个特定的轮子。
| 归档时间: |
|
| 查看次数: |
2179 次 |
| 最近记录: |