亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

縱橫捭闔C++之從異步談起

2019-11-17 05:08:15
字體:
來源:轉載
供稿:網友
簡介一般來說,簡單的異步(Asynchronous)調用是這樣一種調用方式:發起者請求一個異步調用,通知執行者,然后處理其他工作,在某一個同步點等待執行者的完成;執行者執行調用的實際操作,完成后通知發起者。
可以看出,在異步調用中有兩種角色:發起者和執行者,它們都是能主動運行的對象,我們稱為主動對象,同時還有一個同步點,主動對象在同步點協調同步。在本文中,我們討論主要是通用計算機、多進程多線程的分時操作系統上的異步調用。在操作系統的角度上來看,主動對象包括了進程、線程和硬件上的IC等,至于中斷,可以看作總是在某個進程或者線程的上下文借用一下CPU。而同步操作可以通過操作系統得各種同步機制:互斥鎖,信號燈等等來完成。我們可以先看看異步調用在Windows(本文中一般不加指出的話,都是特指NT/2000)讀寫文件中的應用。Windows中的ReadFile和WriteFile都提供了異步的接口。以ReadFile為例,BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWord nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);假如最后一個參數lpOverlapped不為NULL,并且文件以FILE_FLAG_OVERLAPPED標志打開,那么這個調用就是異步的:ReadFile會馬上返回,假如操作沒有馬上完成(返回FALSE并且GetLastError()返回ERROR_IO_PENDING),那么調用者可以在某個時刻通過WaitForSingleObject等函數來等待中的hEvent來等待操作完成(可能已經完成)進行同步,當操作完成以后,可以調用GetOverlappedResult者獲得操作的結果,比如是否成功,讀取了多少字節等等。這里的發起者就是應用程序,而執行者就是操作系統本身,至于執行者是怎么執行的,我們會在后面的篇幅討論。而兩者的同步就是通過一個Windows Event來完成。把這個異步調用的過程再抽象和擴展一些,我們可以把異步調用需要解決的問題歸結為兩個:一個是執行的動力,另一個是主動對象的調度。簡單來說,前者是各個主動對象(線程、進程或者一些代碼)是如何獲得CPU,后者是各個主動對象如何協同工作,保證操作的流程是協調正確的。一般來說,進程和線程都可以由操作系統直接調度而獲得CPU,而更細粒度的,比如一些代碼的調度,往往就需要一個更復雜的模型(比如在操作系統內部的實現,這時候線程的粒度太粗了)。而主動對象的調度,當參與者較少的時候,可以通過基本的同步機制來完成,在更復雜的情況下,可能通過一個schedule機制來做會更實際一些。動力和調度如前所述,異步調用主要需要解決兩個問題:執行的動力和執行的調度。最普遍的情況就是,一個主導流程的調用者進程(線程),一個或多個工作者進程(線程),通過操作系統提供的同步機制來完成異步調用。這個同步機制在擴展化的情形下,是一個或多個柵欄Barrier,對應于每個同步的執行點。所有需要在這個執行點同步的主動對象會等待相應的Barrier,直到所有對象都完成。在一些簡化的情形,比如說工作者并不關心調用者的同步,那么這個Barrier可以簡化成信號燈,在只有一個工作者的情況下,可以簡化成一個Windows事件Event或者條件變量 Condition Variable?,F在來考慮復雜的情形。假設我們用一些線程來協作完成一項工作,各個線程的執行之間有先后順序上的限制,而操作系統就是這項工作的調度者,負責在適當的時候調度適當的線程來獲得CPU。顯然,并發執行中的一個線程對于另外一個線程來說,本質上就是異步的,假如它們之間有調用關系,那也就是一個異步調用。而操作系統可以通過基本的同步機制使得合適的線程才被調度,其他未完成的線程則處于等待狀態。舉例說,我們有4個線程A,B,C,D來完成一項工作,其中的順序限制是A>B;C>D,“>”表示左邊的線程完成必須先于右邊的線程執行,而“;”表示兩個線程可以同時進行。同時假設B的一個操作需要調用C來完成,顯而易見,這時候這個操作就是一個異步調用。我們可以在每個“>”的位置設定一個同步點,然后通過一個信號燈來完成同步。線程B,C等待第一個信號燈,而D會等待第二個信號燈。這個例子的動力和調度都是通過操作系統的基本機制(線程調度和同步機制)來完成。把這個過程抽象一下,可以描述為:若干個主動對象(包括代碼)協調來完成一項工作,通過一個調度器來調度,實際上,這個調度器可能只是一些調度規則。顯然,進程或者線程只要被調度就能獲得CPU,所以我們主要考慮代碼(比如一個函數)怎么樣才能獲得執行。用工作者線程來調用這個函數顯然是直觀和通用的一個方案。事實上,在用戶空間(user space)或者用戶態(user mode),這個方法是很常用的。而在內核態(kernel mode),則可以通過中斷來獲得CPU,這個通過注冊IDT入口和觸發軟中斷就可以完成。硬件設備上的IC是另一個動力之源。而主動對象的調度,最基本的也是前面說的各種同步機制。另一個常用的機制就是回調函數,需要注重的是,回調函數一般會發生在跟調用者不一樣的上下文,比如說同一個進程的不同線程,這個差別會帶來一些限制。假如需要回調發生在調用者的進程(線程)上下文,則需要一些類似Unix下的signal或者Windows下的APC機制,這一點我們在后面會有所闡述。那么在回調函數里面一般作些什么事情呢?最常用的,跟同步機制結合在一起,當然就是釋放一個互斥鎖,信號燈或者Windows Event(Unix的條件變量)等等,從而使得等待同步的其他對象可以得到調度而重新執行,實際上,也可以看作是通知調度器(操作系統)某些主動對象(等待同步的)可以重新被調度了,從而調度器重新調度。但是對于另外一些調度器,在這個過程中可能不需要同步對象的參與。在一些極端一些的例子里,調度甚至不要求嚴格有序的。在實際應用中,根據環境的限制,異步調用的動力和調度的實現方式可以有很大差別。我們會在后面的例子里加以說明。 操作系統中的異步:Windows的異步I/O。Windows NT/2000是一個搶占式的分時操作系統。Windows的調度單位是線程,它的 I/O架構是完全異步的,也就是說同步的I/O實際上都基于異步I/O來完成。一個用戶態的線程請求一個I/O的時候會導致一個運行狀態從user mode到kernel mode的轉變(操作系統把內核映射到每個進程的2G-4G的地址上,對于每個進程都是一樣的)。這個過程是通過中斷調用內核輸出的一些System Service來完成,比如說ReadFile實際上會執行NtReadFile(ZwReadFile),需要注重的是,運行上下文仍然是當前線程。NtReadFile的實現則基于Windows內核的異步I/O框架,在I/O Manager的協助下完成。需要指出的是,I/O Manager只是由若干API構成的一個抽象概念,并沒有一個真正的I/O Manager線程在運行。Windows的I/O驅動程序是層次堆積的。每個驅動程序會提供一致的接口以供初始化、清理和功能調用。驅動程序的調用基于I/O請求包(I/O Request Packet, IRP),而不是像普通的函數調用那樣使用棧來傳遞參數。操作系統和PnP治理器根據注冊表在適當的時機初始化和清理相應的驅動程序。在一般的功能調用的時候,IRP里面會指定功能調用號碼以及相應的上下文或者參數(I/O stack location)。一個驅動程序可能調用別的驅動程序,這個過程可能是同步的(線程上下文不改變),也可能是異步的。NtReadFile的實現,大致是向最上層的驅動程序發出一個或多個IRP,然后等待相應事件的完成(同步的情況),或者直接返回(帶Overlapped的情況),這些都在發起請求的線程執行。當驅動程序處理IRP的時候,它可能馬上完成,也可能在中斷里才能完成,比如說,往硬件設備發出一個請求(通??梢允菍慖/O port),當設備完成操作的時候會觸發一個中斷,然后在中斷處理函數里得到操作結果。Windows有兩類中斷,硬件設備的中斷和軟中斷,分成若干個不同的優先級(IRQL)。軟中斷主要有兩種:DPC(Delayed PRocedure Call)和APC(Asynchronous Procedure Call),都處于較低的優先級。驅動程序可以為硬件中斷注冊ISR(Interrupt Service Routine),一般就是修改IDT某個條目的入口。同樣,操作系統也會為DPC和APC注冊適當的中斷處理例程(也是在IDT中)。值得指出的是,DPC是跟處理器相關的,每個處理器會有一個DPC隊列,而APC是跟線程相關的,每個線程會有它的APC隊列(實際上包括一個Kernel APC隊列和User APC隊列,它們的調度策略有所區別),可以想象,APC并不算嚴格意義上的中斷,因為中斷可能發生在任何一個線程的上下文中,它被稱為中斷,主要是因為IRQL的提升(從PASSIVE到APC),APC的調度一般在線程切換等等情形下進行。當中斷發生的時候,操作系統會調用中斷處理例程,對于硬件設備的ISR,一般處理是關設備中斷,發出一個DPC請求,然后返回。不在設備的中斷處理中使用太多的CPU時間,主要考慮是否則可能丟失別的中斷。由于硬件設備中斷的IRQL比DPC中斷的高,所以在ISR里面DPC會阻塞,直到ISR返回IRQL回到較低的水平,才會觸發DPC中斷,在DPC中斷里執行從硬件設備讀取數據以及重新請求、開中斷等操作。ISR或者DPC可能在任何被中斷的線程上下文(arbitrary thread context)執行,事實上線程的上下文是不可見的,可以認為是系統借用一下時間片而已??偟膩碚f,Windows的異步I/O架構中,主要有兩種動力,一是發起請求的線程,一部分內核代碼會在這個線程上下文執行,二是ISR和DPC,這部分內核代碼會在中斷里完成,可能使用任何一個線程的上下文。而調度常見使用回調和事件(KEVENT),比如說在往下一層的驅動程序發出請求的時候,可以指定一個完成例程Completion Routine,當下層的驅動完成這個請求的時候會調用這個例程,而往往在這個例程里,就是簡單的觸發一下一個事件。 另外可以順便提一下linux。Linux 2.6也有類似的中斷機制,它有更多的軟中斷優先級,即不同優先級的softirq,而類似于DPC,Linux也提供了專門的軟中斷,對應DPC的就是tasklet。Linux沒有一個像windows這么一致的層次驅動程序架構,所以它的異步I/O稍微粗糙一些,主要是通過以前的一些阻塞點,現在直接返回-EIOCBRETRY,而讓調用者在合適的時機繼續重試。在這個方法中,可以認為整個操作由一個函數完成,每次操作有進展時,都把這個函數從頭執行一遍,當然已經完成的部分就不會再有實際的I/O。這樣的最大好處是原有的文件系統和驅動程序不用完全重寫。而對于同步調用,只要阻塞就可以了,這樣對系統的修改較小。這時候,要提供POSIX aio的語義,就可能需要提供一些用戶線程來完成重試的過程了(回想Windows可以通過中斷和DPC完成的)。而對于Solaris,也是類似的處理,假如設備支持異步I/O,那就通過中斷可以完成,否則就使用內部的LWP來模擬。   應用程序:一個異步的HTTP服務器的設計


  假設我們要設計一個HTTP服務器,它的設計目標包括:高并發性、精簡(部分支持HTTP/1.1)、支持plug-in結構。在不少場合可能都有這個需求??傮w上來說,HTTP服務器可以類比成一個基于多線程的操作系統:OS調度每個工作線程在適當的時候獲得執行,而工作線程提供服務(也就是處理HTTP請求)。在這個基礎上,主要的考慮就是調度粒度的大小,粒度太大的時候并發性會降低,而粒度太小又可能因為任務切換(考慮OS的Context Switching)而導致效率降低,所以這又是一個折衷的結果。類似于Apache(以及其他的HTTP服務器),我們可以把一個HTTP處理過程分為若干個狀態,基于這些狀態可以構造出一個HTTP處理的狀態機。這種情況下,我們就可以把每個狀態的處理作為調度的粒度。一個調度過程就是:一個工作線程從全局的任務隊列里取出一個HTTP_Context結構;根據當前的狀態完成相應處理;然后根據狀態機設置下一個狀態;再放回到全局的任務隊列里。這樣子,若干個HTTP狀態就可以通過這個調度策略構成一個完整HTTP處理過程。顯而易見,一個狀態對于下一個狀態處理的調用都可以認為是異步的。一個HTTP狀態機的設計如下圖所示。

    縱橫捭闔C++之從異步談起
圖1. HTTP狀態機
  工作線程的函數其實就是兩個操作:從狀態隊列里取出一個HTTP_Context,調用HTTP_Context的service()函數,周而復此。在這個架構上,就很輕易引入異步I/O和Plug-in的機制了。事實上我們也可以使用基于事件(例如select/poll)的I/O策略來模擬異步I/O,實現中使用一個用戶線程就可以了。

  對于異步I/O和Plug-in的調用,我們也是采用類似于Linux 2.6里面aio的重試方案,而異步完成的時候采用回調函數。在某個狀態上,假如系統需要I/O操作(recv或者send),則會請求一個異步I/O(操作系統提供的異步I/O或者由用戶線程模擬的異步I/O),這時候相應的HTTP_Context不會重新回到狀態隊列里,而在I/O完成的回調函數里面才會重新放回到狀態隊列,得到重新調度的機會。HTTP_Context得到重新調度的時候會檢查I/O狀態(這個可以通過一些標志位來完成),假如已經完成,則處理然后設置下一狀態,重新調度,否則可以重新請求一個新的I/O請求。Plug-in也可以使用類似的方案,比如說一個Plug-in要跟外部的一個服務器通信,這時候就可以在通信完成的時候才把HTTP_Context重新放回到狀態隊列。顯然,Plug-in跟HTTP狀態是多對多的關系,一個Plug-in可以在若干個關心的狀態注冊自身,同時還可以設置一些short-path來提高處理的效率。

  結論

  總的來說,異步調用的設計和應用歸根結底就是對多個主動對象的治理問題:如何提供執行的動力以及如何保證執行的順序邏輯。主要考慮的問題是主動對象的粒度以及執行方式,同步或者回調來完成順序的調度,或者使用近似的調度而加一些魯棒的錯誤處理機制來保證語義的正確。后者可以考慮在使用基于事件的socket的時候,readable事件的通知可以是冗余的,或者說可以比實際中發生的readable事件更多,這個時候使用非阻塞的socket,有些read()(或者recv())會直接返回EWOULDBLOCK,系統只要考慮處理這種情況(使用non blocking socket而不是blocking socket),當例外的情況不多的時候是可以接受的。這時候可以說事件的報告就只是近似的。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
97精品视频在线| 亚洲高清久久久久久| 国产精品午夜国产小视频| 亚洲精品久久久久中文字幕欢迎你| 久久不射电影网| 亚洲免费中文字幕| 日本久久久久亚洲中字幕| 色老头一区二区三区| 国产亚洲欧洲高清| 久久久在线观看| 精品magnet| 久久成人18免费网站| 欧美激情在线有限公司| 国产v综合ⅴ日韩v欧美大片| 国产亚洲精品久久久久久777| 国产狼人综合免费视频| 亚洲欧美自拍一区| 黑人精品xxx一区一二区| 欧美精品999| 日韩在线观看免费全| 久久伊人精品一区二区三区| 亚洲国产精彩中文乱码av在线播放| 欧美小视频在线观看| 亚洲毛茸茸少妇高潮呻吟| 亚州精品天堂中文字幕| 日韩国产欧美精品在线| 国产欧美精品va在线观看| 日韩精品有码在线观看| 亚洲精品视频免费| 亚洲成年人在线| 国产免费成人av| 亚洲自拍欧美色图| 国产视频福利一区| 日本a级片电影一区二区| 亚洲精品久久久久久久久久久久久| 在线观看国产精品91| 最近2019年中文视频免费在线观看| 91精品在线观看视频| 久久久精品一区二区三区| 欧美视频在线看| 福利视频第一区| 精品国产一区二区三区久久狼黑人| 久久久亚洲精选| 国产性猛交xxxx免费看久久| 茄子视频成人在线| 色噜噜狠狠狠综合曰曰曰| 久久国产精品久久久| 欧洲永久精品大片ww免费漫画| 91亚洲va在线va天堂va国| 国产精品美女免费| 亚洲字幕一区二区| 成人黄色午夜影院| 久久99久久亚洲国产| 日韩av在线免播放器| 亚洲乱码一区av黑人高潮| 夜夜嗨av色一区二区不卡| 欧美黄色片在线观看| 日本不卡高字幕在线2019| 欧美另类在线观看| 国产精品美乳在线观看| 欧美日韩中文在线| 91老司机精品视频| 欧美亚洲伦理www| 国内伊人久久久久久网站视频| 精品女同一区二区三区在线播放| 国产精品精品一区二区三区午夜版| 在线观看欧美www| 国产成人高清激情视频在线观看| 亚洲自拍偷拍网址| 日韩在线资源网| 红桃视频成人在线观看| 国产精品视频久久| 91久久精品美女高潮| 一区二区三区天堂av| 亚洲人午夜色婷婷| 久久久精品一区二区三区| 国产精品高潮在线| 久久综合电影一区| 性欧美暴力猛交69hd| 国产精品电影在线观看| 日本成人在线视频网址| 91精品视频大全| 国产精品福利观看| 日韩欧美国产黄色| 91人人爽人人爽人人精88v| 国产精品美女在线| 日韩日本欧美亚洲| 亚洲aaaaaa| 国产精品久久久久久一区二区| 日韩电影大片中文字幕| 日本在线观看天堂男亚洲| 国产精品视频不卡| 成人免费在线视频网址| 国产成人精品在线视频| 日韩电视剧免费观看网站| 中文字幕亚洲精品| 久久久精品日本| 日韩中文综合网| 欧美激情久久久| 国产精品久久久久久久久粉嫩av| 98视频在线噜噜噜国产| 91po在线观看91精品国产性色| 国产成人极品视频| 中文一区二区视频| 国产成人一区二区三区小说| 欧美黄色三级网站| 91情侣偷在线精品国产| 色妞色视频一区二区三区四区| 在线亚洲午夜片av大片| 亚洲色图第一页| 最近中文字幕mv在线一区二区三区四区| 欧美国产第二页| 亚洲人成在线免费观看| 91福利视频在线观看| 综合网日日天干夜夜久久| 欧美激情视频网| 欧美日韩国产影院| 欧美激情2020午夜免费观看| 最新69国产成人精品视频免费| 久久久噜久噜久久综合| 国产日韩换脸av一区在线观看| 欧美小视频在线观看| 中文字幕av一区| 久久天天躁狠狠躁夜夜爽蜜月| 久久久久久国产精品| 中文字幕亚洲欧美在线| 一本大道亚洲视频| 日韩电影大全免费观看2023年上| 中文字幕精品一区二区精品| 亚洲第一精品夜夜躁人人爽| 亚洲欧美色婷婷| 中文字幕日韩在线视频| 亚洲综合大片69999| 久热精品视频在线观看一区| 亚洲国产精品成人va在线观看| 久久天堂电影网| 亚洲开心激情网| 精品国产1区2区| 国产日韩欧美另类| 亚洲国产天堂久久综合| 一区二区三区高清国产| 国产美女直播视频一区| 91在线免费视频| 97国产精品视频人人做人人爱| 欧美裸体男粗大视频在线观看| 国产不卡av在线| 国产精品爽爽爽爽爽爽在线观看| 欧美贵妇videos办公室| 久久天堂av综合合色| 久久伊人91精品综合网站| 狠狠综合久久av一区二区小说| 国产亚洲一区二区在线| 国产欧美日韩综合精品| 日韩在线观看电影| 国产亚洲精品久久久优势| 亚洲成人av在线播放| 国产欧美日韩中文字幕在线| 欧美黑人xxx| 久久精品精品电影网| 国产精品久久久久久av下载红粉| 欧美性猛交99久久久久99按摩| 欧美激情中文网| 成人午夜激情免费视频| 91亚洲va在线va天堂va国|