3 2 2 佇列訊息和非佇列訊息

2021-07-16 18:08:23 字數 2007 閱讀 3745

摘錄於《windows程式(第5版,珍藏版).charles.petzold 著》p60

前面提過 windows 將訊息傳送給乙個視窗,意思是說 windows 呼叫了該視窗的視窗過程。但是,乙個 windows 程式同時還具有乙個訊息迴圈使用者從訊息佇列中檢索和分發訊息,其中檢索訊息是通過呼叫 getmessage 實現的,而分發訊息是通過呼叫 dispatchmessage 而實現的。

那麼,是 windows 程式捕獲到訊息(非常類似於字元模式程式對鍵盤輸入的捕獲)然後將這些訊息轉送到某個目的地呢?還是直接從程式外部接收訊息呢?答案是兩者皆有。

訊息既可以是「佇列訊息」,也可以是「非佇列訊息」。佇列訊息是指那些由 windows 放入程式的訊息佇列中的訊息。在程式的訊息迴圈中,訊息被檢索,然後被投遞到視窗過程中。非佇列訊息則是由windows 對視窗過程的直接呼叫而產生的。我們一般說佇列訊息被「投遞」(post)到訊息佇列中,而非佇列訊息則是被「傳送」(send)到視窗過程。無論在哪些情形下,視窗過程都會為視窗獲取所有訊息——無論是佇列訊息還是非佇列訊息。因此,視窗過程實際上是視窗的「訊息中心」。

佇列訊息主要由使用者的輸入產生,主要形式為按鍵訊息(例如 wm_keydown 和 wm_keyup 訊息)、由按鍵產生的字元訊息(wm_char)、滑鼠移動(wm_mousemove)、滑鼠單擊(wm_lbuttondown)等。此外,佇列訊息還包括定時器訊息(wm_timer)、重繪訊息(wm_paint)和退出訊息(wm_quit)。

非佇列訊息則包括佇列訊息以外的其他所有訊息。非佇列訊息通常由呼叫特定的 windows 函式引起。例如,當 winmain 呼叫 createwindow 函式時,windows 就會建立視窗,並在建立過程中向視窗過程傳送一條 wm_create 訊息。當 winmain 呼叫 showwindow 函式時,windows 又會將 wm_size 訊息和 wm_showwindow 訊息傳送給視窗過程。接下來,winmain 又對 updatewindow 進行了呼叫,就這促使 windows 向視窗過程傳送一條 wm_paint 訊息。表明鍵盤或滑鼠輸入的佇列訊息也能夠產生非佇列訊息。例如,當用鍵盤或滑鼠選擇某個選單項時,鍵盤或滑鼠訊息會進入訊息佇列,而最終表明有某選單項被選中的 wm_command 訊息卻是乙個非佇列訊息。

這個過程顯然十分複雜。但幸運的是,這些複雜性大部分都由 windows 承擔了。從視窗過程的視角看,這些訊息是以有序、同步的方式到來的。視窗過程可以選擇對這些訊息進行某種處理或乾脆直接忽略掉。

在剛才提到訊息是以有序、同步的方式到來時,這句話的第一層含義是指訊息與硬體中斷不同。在視窗過程處理某一訊息的過程中,程式不會被其他訊息突然中斷。

雖然 windows 程式可有多個執行執行緒,但每個執行緒的訊息佇列僅為那些其視窗過程在該執行緒內執行的視窗進行訊息處理。換言之,訊息迴圈和視窗過程不是併發執行的。當乙個訊息迴圈從其自身的訊息佇列中檢索訊息,並呼叫 dispatchmessage 函式將檢索到的訊息傳送給視窗過程時,只有在視窗過程將控制權返還給 windows 後,dispatchmessage 才會返回。

但是,視窗過程可以呼叫為其傳送其他訊息的函式。這種情形下,在該函式呼叫返回之前,視窗過程必須將第二個訊息處理完畢,此時視窗過程才處理前一條訊息。例如,當乙個視窗過程呼叫 updatewindow 時,windows 會以一條 wm_paint 訊息來呼叫視窗過程。當視窗過程處理完 wm_paint 訊息後,updatewindow 呼叫才將控制權返還給視窗過程。

這就意味著視窗過程必須是可重入的(reentrant)。在大多數情形下,這並不會帶來什麼問題,但是對此必須做到心中有數。例如,假定在視窗過程處理某條訊息期間,你對靜態變數進行了設定,接著又呼叫了乙個 windows 函式。當該函式返回時,你能確保這個變數仍然跟先前一樣嗎?我們的確無法保證這一點,因為如果你所呼叫的特定 windows 函式產生了另外一條訊息,且視窗過程在處理第二條訊息期間對該變數進行了修改,則該變數的狀態一定會發生改變。而這也是我們在編譯 windows 程式時需要將某些編譯優化關閉的原因之一。

在許多情況下,視窗過程必須保留其從訊息中獲取的資訊,並在處理其他訊息時使用該資訊。這種資訊必須儲存在視窗過程所定義的靜態變數中,或儲存在全域性變數中。

windows佇列訊息和非佇列訊息的詳細解釋

我們已經談到過,windows給視窗傳送訊息,這意味著windows呼叫視窗訊息處理程式。但是,windows程式也有乙個訊息迴圈,它呼叫getmessage從訊息佇列中取出訊息,並且呼叫dispatchmessage將訊息傳送給視窗訊息處理程式。那麼,windows程式是依次等待訊息 類似於普通程...

訊息佇列 訊息佇列

輪詢排程 一次性分發所有訊息,保證訊息平均分配,不管消費者是否能正常消費 訊息應答 保證消費端能確實消費,不丟失 公平 乙個乙個分發所有訊息,在保證分發到的執行緒確認回覆後,才分發下個訊息給下個空閒的消費者,訊息持久化 保證佇列中的訊息不丟失,包括3要素 交換器 訊息佇列 訊息都必須宣告持久化 發布...

訊息和訊息佇列

在傳統的c 程式當中,我們呼叫 fopen 函式開啟檔案,這個庫函式最終呼叫作業系統 提供的函式 來開啟檔案。而在 windows 中,不僅使用者程式可以呼叫系統的 api函式,反回來,系統也會呼叫使用者程式,這個呼叫是通過訊息來進行的。windows程式設計是一種完全不同於傳統的 dos方式的程式...