无法将'std :: function <void *()>'转换为'void *(*)(void *)'

时间:2018-04-26 20:29:50

标签: c++ pthreads

我是使用<functional>库的新手,所以请耐心等待。以下代码无法编译,出现此错误:

  

错误:无法将参数std::function<void*()>的{​​{1}}转换为void* (*)(void*)3

我不必在我的代码中使用int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*),但我想在放弃和使用标准函数指针之前我是否有解决方案。

以下是我所拥有的:

<functional>

1 个答案:

答案 0 :(得分:3)

我想我可以给这个答案有两种答案:我可以告诉你在C ++中做你想做的事情(开始一个线程)的正确方法,或者我可以告诉你如何挤压将std::function对象转换为pthread_create。第一个具有更多实用价值,而第二个用于解释pthread_create如何处理上下文。两者都有价值,所以:

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

从C ++ 11开始,标准库包含多线程的工具。在您的情况下,我们有一个带返回值的函数,因此任务是

  1. 异步调用该函数,
  2. 在需要时获取返回值。
  3. 最直接的方法是使用std::asyncstd::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();
    

    在您的情况下,您希望调用多个函数并在闲暇时获取返回值,因此您希望将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));
        }
    }
    

    然后,您可以在闲暇时从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);
        }
    }
    

    不是.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通常会为您做到这一点。例如:

    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及其在标准库中的关联类为您解决了所有这些问题,因此无需重新发明这个特定的轮子。