首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法将“std::function<void*()>”转换为“void*(*)(void*)”

无法将“std::function<void*()>”转换为“void*(*)(void*)”
EN

Stack Overflow用户
提问于 2018-04-26 20:29:49
回答 1查看 2.8K关注 0票数 3

我刚开始使用<functional>库,所以请原谅我。以下代码编译失败,出现此错误:

错误:不能将std::function<void*()>转换为void* (*)(void*),将参数3转换为int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)

我不必在代码中使用<functional>,但我想,在放弃和使用标准函数指针之前,我应该先看看是否有解决方案。

我现在拥有的是:

代码语言:javascript
复制
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);
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-26 21:29:30

我想我可以给出两种答案:我可以向您展示如何在C++中执行您想要做的事情(启动线程),或者向您展示如何将std::function对象压缩到pthread_create中。前者具有更多的实用价值,而第二个则用于解释pthread_create如何处理上下文。两者都有价值,所以:

1.如何在新线程中调用std::function<void*()>对象

从C++11开始,标准库包含多线程工具。在您的例子中,我们有一个带有返回值的函数,所以任务是

  1. 异步调用该函数,并且
  2. 当我们需要的时候得到它的返回值。

最直接的方法是使用std::asyncstd::future<void*>。考虑下面这个简单的示例,可以异步地进行one调用:

代码语言:javascript
复制
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();

在您的示例中,您希望调用多个函数并在空闲时获取返回值,因此您希望将std::future<void*>对象存储在某个地方。幸运的是,代码的结构可以大部分保留下来:

代码语言:javascript
复制
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));
    }
}

然后,您可以在空闲时从signal_futures检索返回值。

注意,如果函数没有返回值,则可以使用std::thread而不是std::future

代码语言:javascript
复制
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);
    }
}

而不是对未来的结果进行.get()处理,而是最终对线程进行.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通常会为您做到这一点。例如:

代码语言:javascript
复制
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);

注意,我不建议这样做。它很难看,上面的评论中提到了这个问题。标准库中的std::thread及其相关类为您解决了所有这些问题,因此没有必要重新发明这个特殊的轮子。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50051364

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档