进程同步与异步概念
http://blog.csdn.net/zevin/article/details/8779009
進程同步:
我們把異步環境下的一組并發進程因直接制約而互相發送消息、進行互相合作、互相等待,使得各進程按一定的速度執行的過程稱為進程間的同步。具有同步關系的一組并發進程稱為 合作進程 ,合作進程間互相發送的信號稱為消息或事件。 如果我們對一個消息或事件賦以唯一的消息名,則我們可用過程 wait (消息名) 表示進程等待 合作進程 發來的消息,而用過程signal (消息名) 表示向合作進程發送消息。另外,可以通過“信號量”來實現進程同步。
上面我們用wait(消息名)與signal(消息名)的方式,描述了進程同步的一種實現方法。事實上,使用信號量的方法也可實現進程間的同步。 一般來說,我們也可以把各進程之間發送的消息作為信號量看待。與進程互斥時不同的是,這里的信號量只與制約進程及被制約進程有關而不是與整組并發進程有關。因此,我們稱該信號量為私用信號量(Private Semaphore)。一個進程Pi的私用信號量Semi是從制約進程發送來的進程Pi的執行條件所需要的消息。與私用信號量相對應,我們稱互斥時使用的信號量為公用信號量。
asynchronous call(異步調用)
一個可以無需等待被調用函數的返回值就讓操作繼續進行的方法,(多用“多線程”來實現)。
舉例:
異步調用就是你 喊 你朋友吃飯 ,你朋友說知道了 ,待會忙完去找你 ,你就去做別的了。 同步調用就是你 喊 你朋友吃飯 ,你朋友在忙 ,你就一直在那等,等你朋友忙完了 ,你們一起去。
實戰用法
操作系統發展到今天已經十分精巧,線程就是其中一個杰作。操作系統把 CPU 處理時間劃分成許多短暫時間片,在時間 T1 執行一個線程的指令,到時間 T2又執行下一線程的指令,各線程輪流執行,結果好象是所有線程在并肩前進。這樣, 編程時可以創建多個 線程,在同一期間執行,各線程可以“并行”完成不同的任務。 在 單線程方式下,計算機是一臺嚴格意義上的馮·諾依曼式機器,一段代碼調用另一段代碼時,只能采用 同步調用,必須等待這段代碼執行完返回結果后,調用方才能繼續往下執行。有了 多線程的支持,可以采用異步調用,調用方和被調方可以屬于兩個不同的線程,調用方啟動被調方線程后,不等對方返回結果就繼續執行后續代碼。被調方執行完畢后,通過某種手段通知調用方:結果已經出來,請酌情處理。 計算機中有些處理比較耗時。調用這種處理代碼時,調用方如果站在那里苦苦等待,會嚴重影響程序性能。例如,某個程序啟動后如果需要打開文件讀出其中的數據,再根據這些數據進行一系列初始化處理,程序主窗口將遲遲不能顯示,讓用戶感到這個程序怎么等半天也不出來,太差勁了。借助異步調用可以把問題輕松化解:把整個初始化處理放進一個單獨線程, 主線程啟動此線程后接著往下走,讓主窗口瞬間顯示出來。等用戶盯著窗口犯呆時,初始化處理就在背后悄悄完成了。程序開始穩定運行以后,還可以繼續使用這種技巧改善人機交互的瞬時反應。用戶點擊鼠標時,所激發的操作如果較費時,再點擊鼠標將不會立即反應,整個程序顯得很沉重。借助異步調用處理費時的操作,讓 主線程隨時恭候下一條消息,用戶點擊鼠標時感到輕松快捷,肯定會對軟件產生好感。異步調用外部數據處理
異步調用用來處理從外部輸入的數據特別有效。假如計算機需要從一臺低速設備索取數據,然后是一段冗長的數據處理過程,采用 同步調用顯然很不合算:計算機先向 外部設備發出請求,然后等待數據輸入;而外部設備向計算機發送數據后,也要等待計算機完成數據處理后再發出下一條數據請求。雙方都有一段等待期,拉長了整個處理過程。其實,計算機可以在處理數據之前先發出下一條數據請求,然后立即去處理數據。如果數據處理比 數據采集快,要等待的只有計算機, 外部設備可以連續不停地采集數據。如果計算機同時連接多臺輸入設備,可以輪流向各臺設備發出數據請求,并隨時處理每臺設備發來的數據,整個系統可以保持連續高速運轉。 編程的關鍵是把數據索取代碼和數據處理代碼分別歸屬兩個不同的線程。數據處理代碼調用一個數據請求異步函數,然后徑自處理手頭的數據。待下一組數據到來后,數據處理線程將收到通知,結束 wait 狀態,發出下一條數據請求,然后繼續處理數據。 異步調用時,調用方不等被調方返回結果就轉身離去,因此必須有一種機制讓被調方有了結果時能通知調用方。在同一進程中有很多手段可以利用,筆者常用的手段是回調、 互斥對象和消息。 回調方式很簡單:調用異步函數時在參數中放入一個函數地址,異步函數保存此地址,待有了結果后回調此函數便可以向調用方發出通知。如果把異步函數包裝進一個對象中,可以用事件取代 回調函數地址,通過事件處理例程向調用方發通知。 mutex是 Windows系統提供的一個常用同步對象,以在 異步處理中對齊不同線程之間的步點。如果調用方暫時無事可做,可以調用 wait 函數等在那里,此時 mutex處于 nonsignaled 狀態。當被調方出來結果之后,把 mutex對象置于 signaled 狀態,wait函數便自動結束等待,使調用方重新動作起來,從被調方取出處理結果。這種方式比回調方式要復雜一些,速度也相對較慢,但有很大的靈活性,可以搞出很多花樣以適應比較復雜的處理系統。 借助 Windows消息發通知是個不錯的選擇,既簡單又安全。程序中定義一個用戶消息,并由調用方準備好消息處理例程。被調方出來結果之后立即向調用方發送此消息,并通過WParam 和 LParam 這兩個參數傳送結果。消息總是與窗口 handle關聯,因此調用方必須借助一個窗口才能接收消息,這是其不方便之處。另外,通過消息聯絡會影響速度,需要高速處理時回調方式更有優勢。 如果調用方和被調方分屬兩個不同的進程,由于內存空間的隔閡,一般是采用 Windows消息發通知比較簡單可靠,被調方可以借助消息本身向調用方傳送數據。 event對象也可以通過名稱在不同進程間共享,但只能發通知,本身無法傳送數據,需要借助 Windows 消息和 FileMapping等內存共享手段或借助 MailSlot 和 Pipe 等通信手段。異步調用原理
異步調用原理并不復雜,但實際使用時容易出莫名其妙的問題,特別是不同線程共享代碼或共享數據時容易出問題, 編程時需要時時注意是否存在這樣的共享,并通過各種 狀態標志避免沖突。Windows 系統提供的 mutex 對象用在這里特別方便。mutex同一時刻只能有一個管轄者。一個線程放棄管轄權后,另一線程才能接管。當某線程執行到敏感區之前先接管 mutex,使其他線程被 wait函數堵在身后;脫離敏感區之后立即放棄管轄權,使 wait函數結束等待,另一個線程便有機會光臨此敏感區。這樣就可以有效避免多個線程進入同一敏感區。 由于異步調用容易出問題,要設計一個安全高效的編程方案需要比較多的設計經驗,所以最好不要濫用異步調用。 同步調用畢竟讓人更舒服些:不管程序走到哪里,只要死盯著移動點就能心中有數,不至于象異步調用那樣,總有一種四面受敵、惶惶不安的感覺。必要時甚至可以 把異步函數轉換為同步函數。方法很簡單:調用異步函數后馬上調用 wait 函數等在那里,待異步函數返回結果后再繼續往下走。異步調用使用方法
測試方法和異步委托
四個示例全部使用同一個長期運行的測試方法 TestMethod。該方法顯示一個表明它已開始處理的控制臺信息,休眠幾秒鐘,然后結束。TestMethod 有一個 out 參數(在 Visual Basic 中為 ByRef),它演示了如何將這些參數添加到 BeginInvoke 和 EndInvoke 的簽名中。您可以用類似的方式處理 ref 參數(在 Visual Basic 中為 ByRef)。 下面的代碼示例顯示 TestMethod 以及代表 TestMethod 的委托;若要使用任一示例,請將示例代碼追加到這段代碼中。 注意 為了簡化這些示例,TestMethod 在獨立于 Main() 的類中聲明。或者,TestMethod 可以是包含 Main() 的同一類中的 static 方法(在 Visual Basic 中為 Shared)。使用 EndInvoke 等待異步調用
異步執行方法的最簡單方式是以 BeginInvoke 開始,對 主線程執行一些操作,然后調用 EndInvoke。EndInvoke 直到C#異步調用完成后才返回。這種技術非常適合文件或網絡操作,但是由于它阻塞 EndInvoke,所以不要從用戶界面的服務 線程中使用它。使用 WaitHandle 等待異步調用
等待 WaitHandle 是一項常用的 線程同步技術。您可以使用由 BeginInvoke 返回的 IAsyncResult 的 AsyncWaitHandle 屬性來獲取 WaitHandle。C#異步調用完成時會發出 WaitHandle 信號,而您可以通過調用它的 WaitOne 等待它。 如果您使用 WaitHandle,則在C#異步調用完成之后,但在通過調用 EndInvoke 檢索結果之前,可以執行其他處理。輪詢異步調用完成
您可以使用由 BeginInvoke 返回的 IAsyncResult 的 IsCompleted 屬性來發現C#異步調用何時完成。從用戶界面的服務 線程中進行C#異步調用時可以執行此操作。輪詢完成允許用戶界面線程繼續處理用戶輸入。總結
- 上一篇: NodeJs ES6 写简单爬虫 爬小说
- 下一篇: 10步Navicat for Mysql