同步并发操作之等待一次性事件

2015-01-27 10:09:13 · 作者: · 浏览: 16

有时候需要用一些后台线程来完成计算,这些计算往往都是一次性的,线程计算完后便结束。这时候可以使用条件变量,但是有点浪费,我们只需要获取一次结果。C++标准库中有头文件 ,很形象“未来”,获取未来计算的结果。

使用std::async来启动一个异步任务。用std::future对象来存储异步任务返回的结果,这个对象存储结果。当我们需要结果时,只需调用get()方法。这时如果还没计算完毕,当前线程会阻塞。

#include
  
   
#include
   
     int find_the_answer_to_ltuae(); void do_other_sutff(); int main() { std::future
    
      the_answer = std::async(find_the_answer_to_ltuae); do_other_sutff(); std::cout << "The answer is " << the_answer.get() << std::endl; return 0; } int find_the_answer_to_ltuae() { return 10; } void do_other_sutff() { std::cout << "do_other_sutff " << std::endl; }
    
   
  


可以像线程那样,向函数传递参数

#include
  
   
#include
   
     #include
    
      struct X { void foo(int, std::string const&); std::string bar(std::string const&); }; X x; auto f1 = std::async(&X::foo, &x, 32, "hello");//p->foo(42,"hello")。p是&x auto f2 = std::async(&X::bar, x, "goodbye");//tmp.bar("goodbye")。x是tmp struct Y { double operator()(double); }; Y y; auto f3 = std::async(Y(), 3.141);//tem(3.141),tmp是Y()的move-constructed auto f4 = std::async(std::ref(y), 2.718);//y(2.718) X baz(X&); std::async(baz, std::ref(x));//调用baz class move_only { public: move_only(); move_only(move_only&&); move_only(move_only const&) = delete; move_only& operator=(move_only&&); move_only& operator=(move_only const&)=delete; void operator()(); }; auto f5 = std::async(move_only());//构造临时对象执行
    
   
  


可以通过传递参数来决定是否启动新的线程或何时启动新线程,

auto f6 = std::async(std::launch::async, Y(), 1.2);//启动新线程执行
auto f7 = std::async(std::launch::deferred, baz, std::ref(x));//调用wait或get后才执行
auto f8 = std::async(
	std::launch::deferred | std::launch::async,
	baz, std::ref(x));//由实现来选择
auto f9 = std::async(baz, std::ref(x));
f7.wait();//执行f7对应的后台线程

结合task和future

可以使用std::packaged_task<>和future结合。当激活std::package_task<>时,调用future的函数。函数返回结果存在关联的数据中。 std::package_task<>的参数是函数签名(像函数指针定义)。例如,void()表示无返回值,无参数的函数;int (std::sgring&,double*)表示函数返回类型为int,参数为string引用和double类型指针。当定义std::package_task<>对象时,必须给出参数和返回类型。 std::future<>的返回类型通过成员函数get_future()获得。 在许多GUI框架中,要求从特定的线程更新GUI。如果一个线程想要更新GUI,它必须给GUI线程发送一个消息。可以通过std::package_task来解决这个问题。
#include
  
   
#include
   
     #include
    
      #include
     
       #include
      
        std::mutex m; std::deque
       
         > tasks; bool gui_shutdown_message_received(); void get_and_process_gui_message(); void gui_thread()//GUI线程 { while(!gui_shutdown_message_received())//收到GUI关闭信息 { get_and_process_gui_message();//处理GUI窗口信息 std::packaged_task
        
          task;//定义任务 { std::lock_guard
         
           lk(m); if(tesks.empty())//任务队列无任务时,执行task() continue; task=std::move(tasks.front()); tasks.pop_front();//任务出列 } task();//执行task } } std::thread gui_bg_thread(gui_thread); template
          
            std::future
           
             post_task_for_gui_thread(Func f) { std::package_task
            
              task(f);//创建task std::future
             
               res=task.get_future(); std::lock_guard
              
                lk(m); tasks.push_back(std::move(task));//把task放到队列 return res; }