zoukankan      html  css  js  c++  java
  • 同步并发操作之等待一次性事件

    有时候须要用一些后台线程来完毕计算,这些计算往往都是一次性的,线程计算完后便结束。

    这时候能够使用条件变量。可是有点浪费,我们仅仅须要获取一次结果。C++标准库中有头文件<future>。非常形象“未来”,获取未来计算的结果。

    使用std::async来启动一个异步任务。用std::future对象来存储异步任务返回的结果。这个对象存储结果。当我们须要结果时,仅仅需调用get()方法。

    这时假设还没计算完成,当前线程会堵塞。

    #include<future>
    #include<iostream>
    
    
    int find_the_answer_to_ltuae();
    void do_other_sutff();
    int main()
    {
    	std::future<int> 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<future>
    #include<iostream>
    #include<string>
    
    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<deque>
    #include<mutex>
    #include<future>
    #include<thread>
    #include<utility>
    
    std::mutex m;
    std::deque<std::packaged_task<void()> > 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<void()> task;//定义任务
    		{
    			std::lock_guard<std::mutex> 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<typename Func>
    std::future<void> post_task_for_gui_thread(Func f)
    {
    	std::package_task<void()> task(f);//创建task
    	std::future<void> res=task.get_future();
    	std::lock_guard<std::mutex> lk(m);
    	tasks.push_back(std::move(task));//把task放到队列
    	return res;
    }

  • 相关阅读:
    JS 实现点击<a> 标签的时候给其换背景
    LeetCode解题思路 (一)
    读书笔记之《操作系统概念》
    读书笔记之《程序员代码面试指南(字符串问题)》
    读书笔记之《程序员代码面试指南(栈和队列)》
    读书笔记之《程序员代码面试指南(数组和矩阵问题)》
    读书笔记之《程序员代码面试指南(位运算及大数据)》
    项目常用功能代码
    读书笔记之《深入理解Java虚拟机》
    读书笔记之《程序员代码面试指南(链表问题)》
  • 原文地址:https://www.cnblogs.com/yjbjingcha/p/6920594.html
Copyright © 2011-2022 走看看