異步模式的實現


什么是異步

異步是當一個調用請求發送給被調用者,而調用者不用等待其結果的返回.實現異步可以采用多線程技術或則交給另外的進程來處理

 

異步的優缺點


1、在設計良好的情況下,可以不是使用或減少共享變量的使用,減少了死鎖的可能


2、編寫異步操作的復雜度高,使用回調函數處理難以調試

 

 

 

異步與多線程

異步與多線程,從辯證關系上來看,異步和多線程並不時一個同等關系,異步是目的,多線程只是我們實現異步的一個手段(線程池).

 

硬件上實現異步


DMA就是直 接內存訪問的意思,也就是說,擁有DMA功能的硬件在和內存進行數據交換的時候可以不消耗CPU資源。只要CPU在發起數據傳輸時發送一個指令,

硬件就開 始自己和內存交換數據,在傳輸完成之后硬件會觸發一個中斷來通知操作完成。這些無須消耗CPU時間的I/O操作正是異步操作的硬件基礎。


軟件上實現異步

上面說了多線程是實現異步的一個手段、但是使用主函數調用異步處理線程的時候,比較難獲取子線程的返回值(實際可以通過使用全局變量、指針、引用、promise+future),總體來說使用比較復雜,所以就有async()函數實現異步

std::async是更高層次上的異步操作,使我們不用關注線程創建內部細節,就能方便的獲取異步執行狀態和結果,還可以指定線程創建策略,應該用std::async替代線程的創建,讓它成為我們做異步操作的首選。

async大概的工作過程是這樣的:

1、furture聲明未來的異步操作的結果

2、promise承諾這個結果的出現

3、packaged_task將異步任務包裝起來,放到線程中執行(lambda 表達式)

4、最后通過wait()和wait_for()來獲取異步任務的完成狀態,根據這個狀態選擇調用get()來獲取這個未來的結果

 

因為一個異步操作我們是不可能馬上就獲取操作結果的,只能在未來某個時候獲取,但是我們可以以同步等待的方式來獲取結果,可以通過查詢future的狀態(future_status)來獲取異步操作的結果。

future_status是一個枚舉的數據類型,有三種狀態:

1、deferred:異步操作還沒開始

2、ready:異步操作已經完成

3、timeout:異步操作超時

 

可以使用future的wait()、wait_for()、wait_untill()來獲取任務的完成狀態

  1、wait()阻塞調用

  2、wait()阻塞一個time_out時間

 

 




async異步調用函數的使用

async(launch,func,args)函數有三個參數,分別是啟動方式、任務函數,參數列表

 

啟動策略有三種方式

1、launch::deferred  : 延遲調用異步函數,延遲到future對象調用get()或者wait()的時候才執行func();如果不調用get()或者wait(),func()不會執行。

2、launch::async      :強制這個異步任務在一個新線程上執行,這意味着,系統必須要創建出一個新線程來運行func(),新線程創建失敗拋出異常

3、launch::async| launch::deferred    : 由系統自行決定選擇那種啟動方式

 

func的類型可以是函數指針、函數對象、lambda表達式

 

 

std::async與std::thread的區別

std::async()與std::thread()最明顯的不同,就是async並不一定創建新的線程

std::thread() 如果系統資源緊張,那么可能創建線程失敗,整個程序可能崩潰。

std::thread()創建線程的方式,如果線程返回值,你想拿到這個值也不容易;

std::async()創建異步任務,可能創建也可能不創建線程;並且async調用方式很容易拿到線程入口函數的返回值。

 

#include<iostream>
#include<thread>
#include<string>
#include<vector>
#include<list>
#include<mutex>
#include<future>
using namespace std;

int mythread() //線程入口函數
{
    cout << "mythread start  " << "threadid= " << this_thread::get_id() << endl; //打印線程id

    chrono::milliseconds dura(5000); //定一個5秒的時間
    this_thread::sleep_for(dura);  //休息一定時常

    cout << "mythread end  " << "threadid= " << this_thread::get_id() << endl; //打印線程id

    return 5;
}
int main()
{

    future<int> result = async(mythread);//默認方式啟動線程、無參數傳遞


    //獲取異步任務的完成狀態
    //future_status是一個枚舉類型的值,wait()和wait_for()返回該枚舉類型的值
    //wait()會阻塞調用線程,直到異步任務完成取消阻塞
    //wait_for(time_out)會阻塞一段時間,在time_out時間內返回並結束阻塞

    

    while (1) {

        future_status status = result.wait_for(std::chrono::seconds(1));//每一秒鍾輪詢一次狀態
        //異步操作還沒被調用
        if (status == future_status::deferred)
        {
            //調用開始
            cout << result.get() << endl;
        }
        //異步操作超時
        else if (status == future_status::timeout)
        {
            cout << "超時:表示線程還沒執行完!" << endl;
        }
        //異步調用結束
        else if (status == future_status::ready)
        {
            //表示線程成功返回
            cout << "線程成功執行完畢,返回!" << endl;
            cout << result.get() << endl;
            break;
        }
    }
    

    cout << "Finish!" << endl;
    system("pause");
    return 0;
}

 

 

參考博客: https://www.cnblogs.com/qicosmos/p/3534211.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM