【问题标题】:Error about std::promise in C++C++ 中关于 std::promise 的错误
【发布时间】:2013-08-14 21:23:52
【问题描述】:

我正在尝试将我的类实例传递给线程并从线程返回已处理的对象。我在谷歌上搜索了 C++ 多线程,发现 std::promising 可能会有所帮助。

但是,我一开始就被困住了。这是我的代码:

void callerFunc()
{
    //...
    std::promise<DataWareHouse> data_chunks;    
    // DataWareHouse is my customized class
    //data_chunks has a vector<vector<double>> member variable
    std::thread(&run_thread,data_chunks);
    // ............
}

void run_thread(std::promise<DataWareHouse> data_chunks)
{
    // ... 
    vector<vector<double>> results;
    // ...
    data_chunks.set_value(results);
}

以上代码产生错误:

 `error C2248: 'std::promise<_Ty>::promise' : cannot access private member declared in class 'std::promise<_Ty>'`

我可以知道我错了什么以及如何解决它吗?

非常感谢。 :-)

【问题讨论】:

    标签: c++ multithreading return-value std promise


    【解决方案1】:

    您的第一个问题是您正在使用std::thread -- std::thread 是一个低级类,您应该在其上构建更高的抽象。线程是C++11中C++新标准化的,所有粗糙的部分还没有归档。

    在 C++11 中使用线程的三种不同模式可能对您有用。

    首先,std::async。第二,std::threadstd::packaged_task混合。第三,处理原始的std::threadstd::promise

    我将说明第三个,它是最低级别且最危险的,因为这是您所要求的。我建议查看前两个选项。

    #include <future>
    #include <vector>
    #include <iostream>
    
    typedef std::vector<double> DataWareHouse;
    
    void run_thread(std::promise<DataWareHouse> data_chunks)
    {
      DataWareHouse results;
      results.push_back( 3.14159 );
      data_chunks.set_value(results);
    }
    
    std::future<DataWareHouse> do_async_work()
    {
      std::promise<DataWareHouse> data_chunks;  
      std::future<DataWareHouse> retval = data_chunks.get_future();
      // DataWareHouse is my customized class
      //data_chunks has a vector<vector<double>> member variable
      std::thread t = std::thread(&run_thread,std::move(data_chunks));
      t.detach(); // do this or seg fault
      return retval;
    }
    
    int main() {
      std::future<DataWareHouse> result = do_async_work();
      DataWareHouse vec = result.get(); // block and get the data
      for (double d: vec) {
        std::cout << d << "\n";
      }
    }
    

    Live example

    使用std::async,您将有一个返回DataWareHouse 的函数,它会直接返回std::future&lt;DataWareHouse&gt;

    使用std::packaged_task&lt;&gt;,它会将您的run_thread 转换为可以执行的packaged_task,并从中提取std::future

    【讨论】:

      【解决方案2】:

      std::promise&lt;&gt; 是不可复制的,在调用run_thread() 时,您正在隐式尝试调用复制构造函数。错误消息告诉您不能使用复制构造函数,因为它被标记为私有。

      您需要通过引用 (std::promise&lt;DataWareHouse&gt; &amp;) 传递承诺。如果callerFunc() 保证在run_thread() 完成对象之前不会返回,这是安全的(否则您将使用对已销毁的堆栈分配对象的引用,我不必解释为什么这很糟糕)。

      【讨论】:

      • @Yakk:调用者需要稍后访问 Promise 才能接收结果。如果它被移到线程中,它就无法做到这一点。
      • @MikeSeymour 为什么不从std::promise 中提取std::future,然后将movestd::promise 提取到线程中?这消除了讨厌的引用共享线程问题。
      • @Yakk:为什么不呢?那将是比我更好的答案。尽管使用std::async 可能会更好,而不是重新实现它...
      【解决方案3】:

      你试图通过值将承诺传递给线程;但是您需要通过引用传递以将结果返回给调用者的承诺。 std::promise 是不可复制的,为了防止这个错误。

      std::thread(&run_thread,std::ref(data_chunks));
                              ^^^^^^^^
      
      void run_thread(std::promise<DataWareHouse> & data_chunks)
                                                  ^
      

      【讨论】:

        【解决方案4】:

        错误是告诉你不能复制std::promise,你可以在这里做:

        void run_thread(std::promise<DataWareHouse> data_chunks)
        

        这里:

        std::thread(&run_thread,data_chunks); // makes copy of data_chunks
        

        你应该传递一个参考:

        void run_thread(std::promise<DataWareHouse>& data_chunks);
        //                                         ^
        

        然后将std::reference_wrapper 传递给线程,否则它也会尝试复制承诺。使用std::ref 很容易做到这一点:

        std::thread(&run_thread, std::ref(data_chunks));
        //                       ^^^^^^^^
        

        显然data_chunks 在线程完成运行之前必须处于活动状态,因此您必须加入callerFunc() 中的线程。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-11-10
          • 2021-11-13
          • 1970-01-01
          • 2012-05-16
          • 2014-09-26
          • 1970-01-01
          • 1970-01-01
          • 2014-01-19
          相关资源
          最近更新 更多