最近琢磨windows的消息機制,發現一些有趣的地方,可能是對的,也可能是錯的,分享出來讓大家評判評判。
1:每個線程都有消息隊列
不僅僅是有窗口的線程,沒有窗口的線程也有消息隊列!編寫一個win32控制檯程序,代碼如下:
#include<windows.h>
void main()
{
DWORD dwThread = GetCurrentThreadId();
::PostThreadMessage(dwThread,10000,NULL,NULL);
MSG msg;
GetMessage(&msg,NULL,NULL,NULL);
}
獲取當前線程ID,對當前線程發送線程消息,然後調用GetMessage函數從消息隊列中取消息,看看能不能取到我們之前發出的編號爲10000的消息。
運行發現GetMessage函數成功從消息隊列中取出了我們發送的編號爲10000的消息!我們這個線程沒有窗口、沒有消息循環,但是有消息隊列,消息隊列是windows爲線程提供的。
2:消息隊列的容量有多大?
如果我們不停的發送消息,卻不用GetMessage之類的函數獲取並從消息隊列中移除消息。消息隊列中的消息豈不是越來越多?那麼這個消息隊列究竟有多大容量呢?它最多能容納多少消息?我們編寫如下代碼
#include<windows.h>
void main()
{
DWORD dwThread = GetCurrentThreadId();
for (int i=0;i<1000;i++)
PostThreadMessage(dwThread,10000,NULL,NULL);
int n = 0;
MSG msg;
while(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
{
if (msg.message == 10000)
n++;
}
}
循環調用PostThreadMessage發送1000個消息,然後用PeekMessage取出消息,最後一個參數PM_REMOVE說明每取出一個消息後將該消息從消息隊列中移除。我們用變量n來統計從消息隊列中取出了多少個編號爲10000的消息。這裏爲什麼不用GetMessage呢?因爲GetMessage把消息隊列中的消息取完了以後會阻塞起來一直等待,我們的while循環無法退出,後面的斷點也無法命中。而PeekMessage把消息隊列中的消息取完了以後,取不到消息就返回0,我們的while也就結束了。
運行後發現,果然,n的值爲1000,取出了1000個我們發送的消息。接下來我們再增大消息的發送數量,看看還能取出多少。
這次我們發送了50000個消息,但是運行後發現只從消息隊列中取出了10000個消息!消息隊列的容量爲10000個嗎?我們上網查資料,確實如此。消息隊列的容量默認爲10000個,這個值可以在註冊表中修改。
展開註冊表:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\
找到USERPostMessageLimit 項,發現該項的默認值爲10000。我們可以通過修改該值來改變消息隊列的容量,重啓後生效。