最近面試遇到的Windows相關(guān)的題目
上周準(zhǔn)備在公司內(nèi)部轉(zhuǎn)崗,面了3個(gè)部門(mén)windows客戶端相關(guān)的工作,最終拿到3個(gè)Offer,主要涉及C++和Windows兩大塊內(nèi)容,C++的題目基本都答上了,Windows一直都是我的弱項(xiàng),在這里記錄一下Windows相關(guān)的題目。有些答不上的問(wèn)題就沒(méi)列出來(lái),還有些問(wèn)題忘了,下面的答案有些大部分是我自己的理解,有些是直接從網(wǎng)上copy的,有問(wèn)題大家可以討論。
1:GetMessage和PeekMessage的區(qū)別?
GetMessage:獲取消息隊(duì)列中的一個(gè)消息,存入MSG中,并從消息隊(duì)列中移除,如果消息隊(duì)列中沒(méi)有消息就會(huì)阻塞;
PeekMessage:查看消息,有消息,就將數(shù)據(jù)存入MSG結(jié)構(gòu)中,沒(méi)有消息就返回FALSE,不會(huì)阻塞,但如果沒(méi)有更新區(qū),可以移除WM_PAINT消息,還可以通過(guò)最后一個(gè)參數(shù)來(lái)決定是否從隊(duì)列中移除查看的消息;
2:SendMessage和PostMessage的區(qū)別?怎么跨線程發(fā)消息?怎么跨進(jìn)程發(fā)消息?SendMessage在進(jìn)程間發(fā)消息要注意什么?SendMessage能將消息發(fā)送到消息隊(duì)列嗎?PostMessage可以在進(jìn)程間發(fā)消息嗎??jī)蓚€(gè)線程互相SendMessage會(huì)出問(wèn)題嗎?
SendMessage:將一個(gè)消息發(fā)送到指定窗口的窗口過(guò)程中,等窗口過(guò)程執(zhí)行完了再返回;
PostMessage:將消息發(fā)送到指定窗口所在線程的消息隊(duì)列中,直接返回,消息是否被處理完全不知道;
SendMessage直接調(diào)用窗口過(guò)程,那它是否可以將消息發(fā)送到發(fā)送到線程的消息隊(duì)列中呢?
可以啊,比如發(fā)送一個(gè)WM_PAINT消息,這是一個(gè)隊(duì)列消息,只有存在無(wú)效區(qū)域的情況下,才會(huì)處理WM_PAINT消息;
線程間SendMessage,由于它基本就是調(diào)用指定窗口的窗口過(guò)程,當(dāng)跨線程發(fā)消息的時(shí)候,無(wú)法調(diào)用指定窗口的窗口過(guò)程,在跨線程發(fā)送;
消息的時(shí)候,發(fā)送線程會(huì)先掛起,由系統(tǒng)線程將消息發(fā)送到接收線程的另一個(gè)隊(duì)列中,并設(shè)置QS_SENDMESSAGE標(biāo)志,當(dāng)系統(tǒng)檢測(cè)到這個(gè)標(biāo)志后,就會(huì)處理這個(gè)隊(duì)列的消息,當(dāng)這個(gè)消息被處理之后,調(diào)用SendMessage的線程就會(huì)被喚醒,就繼續(xù)執(zhí)行。
SendMessage是可以跨進(jìn)程發(fā)消息的,通過(guò)FindWindow找到對(duì)方進(jìn)程的窗口句柄,發(fā)一個(gè)消息過(guò)去就行了,由于兩個(gè)進(jìn)程間的內(nèi)存是完全獨(dú)立的,不能發(fā)指針,如果要發(fā)數(shù)據(jù),就用WM_COPYDATA。
PostMessage可以在進(jìn)程間發(fā)消息,但不能結(jié)合WM_COPYDATA使用,WM_COPYDATA通過(guò)內(nèi)存映射在進(jìn)程間傳遞數(shù)據(jù),PostMessage后映射文件的句柄就無(wú)效了。
兩個(gè)線程互相SendMessage可能會(huì)導(dǎo)致死鎖,A線程鎖住一個(gè)資源,向B線程發(fā)一個(gè)消息,A線程掛起,這時(shí)如果B線程在處理A線程的消息需要A線程鎖住的資源,A由于發(fā)給B的消息還沒(méi)有處理完就一直不能返回,鎖也沒(méi)有打開(kāi),B線程又用不了,消息也就處理不完,結(jié)果就死鎖了。
3:Windows是怎么實(shí)現(xiàn)窗口刷新的?怎么實(shí)現(xiàn)窗口的立即刷新?
Update Region不為空時(shí),系統(tǒng)就會(huì)自動(dòng)產(chǎn)生WM_PAINT消息,通過(guò)InvalidateRect和InvalidateRgn可把指定的區(qū)域加到窗口的Update Region中,通過(guò)處理WM_PAINT消息來(lái)實(shí)現(xiàn)窗口的刷新。 系統(tǒng)為什么不在調(diào)用Invalidate時(shí)發(fā)送WM_PAINT消息呢?又為什么非要等應(yīng)用消息隊(duì)列為空時(shí)才發(fā)送WM_PAINT消息呢?這是因?yàn)橄到y(tǒng)把在窗口中的繪制操作當(dāng)作一種低優(yōu)先級(jí)的操作,于是盡可能地推后做。不過(guò)這樣也有利于提高繪制的效率:兩個(gè)WM_PAINT消息之間通過(guò)InvalidateRect和InvaliateRgn使之失效的區(qū)域就會(huì)被累加起來(lái),然后在一個(gè)WM_PAINT消息中一次得到更新,不僅能避免多次重復(fù)地更新同一區(qū)域,也優(yōu)化了應(yīng)用的更新操作。
如果窗口更新的區(qū)域不為空,UpdateWindow函數(shù)通過(guò)發(fā)送一個(gè)WM_PAINT消息來(lái)更新指定窗口的客戶區(qū)。函數(shù)繞過(guò)應(yīng)用程序的消息隊(duì)列,直接發(fā)送WM_PAINT消息給指定窗口的窗口過(guò)程,如果更新區(qū)域?yàn)榭眨瑒t不發(fā)送消息。
WM_PAINT一般在消息隊(duì)列中沒(méi)有消息的時(shí)候才處理,有時(shí)候我們需要立即刷新窗口,那么就需要UpdateWindow函數(shù)了,直接繞過(guò)消息循環(huán),只要更新區(qū)域不為空,將WM_PAINT消息直接發(fā)送到指定窗口過(guò)程即可。
Invalidate(hwnd); //將窗口設(shè)為不可用,導(dǎo)致更新區(qū)域不為空
UpdateWindow(hwnd); //立即刷新窗口
4:Windows消息循環(huán)有哪幾個(gè)函數(shù),各自的作用是什么?消息循環(huán)是怎么退出的?
while(GetMessage(&msg, NULL, 0, 0)) //獲取一個(gè)消息,成功后會(huì)放在msg中。
{
TranslateMessage(&msg); //消息進(jìn)行必要的處理轉(zhuǎn)換。
DispatchMessage(&msg); //調(diào)用WinProc,將msg的各項(xiàng)信息傳遞給WinProc
}
當(dāng)GetMessage獲取到的消息是WM_QUIT,返回的就是FALSE,while循環(huán)就退出了,消息循環(huán)也就終止了。
5:句柄是什么?
句柄就是一個(gè)整數(shù),Windows為每一個(gè)控件指定了一個(gè)唯一的整數(shù),通過(guò)這個(gè)整數(shù)和相關(guān)函數(shù)操作控件。
6:Windows實(shí)現(xiàn)線程間同步有哪些方法?實(shí)現(xiàn)進(jìn)程間同步又有哪些方法?讀寫(xiě)鎖的實(shí)現(xiàn)原理是什么?
1:volatile
2:關(guān)鍵段
3:旋轉(zhuǎn)鎖
4:讀寫(xiě)鎖
5:事件對(duì)象
6:信號(hào)量
7:互斥量
只要是內(nèi)核對(duì)象,就能用于進(jìn)程間的同步,內(nèi)核對(duì)象不屬于任何進(jìn)程,由系統(tǒng)管理。
讀寫(xiě)鎖實(shí)際是一種特殊的自旋鎖,它把對(duì)共享資源的訪問(wèn)者劃分成讀者和寫(xiě)者,讀者只對(duì)共享資源進(jìn)行讀訪問(wèn),寫(xiě)者則需要對(duì)共享資源進(jìn)行寫(xiě)操作。這種鎖相對(duì)于自旋鎖而言,能提高并發(fā)性,因?yàn)樵诙嗵幚砥飨到y(tǒng)中,它允許同時(shí)有多個(gè)讀者來(lái)訪問(wèn)共享資源,最大可能的讀者數(shù)為實(shí)際的邏輯CPU數(shù)。寫(xiě)者是排他性的,一個(gè)讀寫(xiě)鎖同時(shí)只能有一個(gè)寫(xiě)者或多個(gè)讀者 (與CPU數(shù)相關(guān)),但不能同時(shí)既有讀者又有寫(xiě)者。我覺(jué)得他其實(shí)就是對(duì)關(guān)鍵段和內(nèi)核事件對(duì)象的封裝。寫(xiě)的時(shí)候獨(dú)占,讀的時(shí)候共享。
7:模態(tài)窗口的實(shí)現(xiàn)原理?模態(tài)窗口會(huì)導(dǎo)致崩潰嗎?
模態(tài)窗口其實(shí)就是在當(dāng)前窗口調(diào)用系統(tǒng)的消息循環(huán),響應(yīng)用戶的操作,將相關(guān)的消息發(fā)送到對(duì)應(yīng)的窗口。將父窗口設(shè)為不可用,即不能響應(yīng)用戶的操作,在關(guān)閉當(dāng)前窗口的時(shí)候,將父窗口設(shè)為可用,并退出消息循環(huán)。
可能導(dǎo)致窗口崩潰,模態(tài)窗口顯示的時(shí)候,除了父窗口不可用之外,其他的窗口都是可用的,如果需要的一個(gè)資源在別的地方被釋放了,而在模態(tài)窗口中使用的時(shí)候,沒(méi)有判斷可能就會(huì)導(dǎo)致崩潰。
8:你了解沙箱,UAC相關(guān)的知識(shí)嗎?
不了解
9:怎么實(shí)現(xiàn)線程間發(fā)消息?線程的消息隊(duì)列默認(rèn)會(huì)創(chuàng)建嗎?
SendMessage可以再線程間發(fā)消息,PostThreadMessage通過(guò)線程ID可以在線程間發(fā)消息,將消息發(fā)送到指定線程的消息隊(duì)列中。線程的消息隊(duì)列默認(rèn)是不會(huì)創(chuàng)建的,因?yàn)榫€程的消息隊(duì)列并不是必須的。通過(guò)ResumeThread(threadHwnd);可以創(chuàng)建線程的消息隊(duì)列。
10:說(shuō)說(shuō)Windows的內(nèi)存管理,怎么實(shí)現(xiàn)內(nèi)存共享?
FileMapping用于將存在于磁盤(pán)的文件放進(jìn)一個(gè)進(jìn)程的虛擬地址空間,并在該進(jìn)程的虛擬地址空間中產(chǎn)生一個(gè)區(qū)域用于“存放”該文件,這個(gè)空間就叫做 File View,系統(tǒng)并同時(shí)產(chǎn)生一個(gè)File Mapping Object(存放于物理內(nèi)存中)用于維持這種映射關(guān)系,這樣當(dāng)多個(gè)進(jìn)程需要讀寫(xiě)那個(gè)文件的數(shù)據(jù)時(shí),它們的File View其實(shí)對(duì)應(yīng)的都是同一個(gè)File Mapping Object,這樣做可節(jié)省內(nèi)存和保持?jǐn)?shù)據(jù)的同步性,并達(dá)到數(shù)據(jù)共享的目的。
第四輪面試官:如果加班嚴(yán)重你來(lái)嗎?
阿漢:不來(lái)
第四輪面試官:你確定嗎?
阿漢:確定
第四輪面試官:我沒(méi)有問(wèn)題了,你還有什么要問(wèn)的嗎?
接下來(lái)是第五輪面試……我只是內(nèi)部轉(zhuǎn)崗啊,面了五輪整整四個(gè)小時(shí),最后哥還是從了這個(gè)部門(mén)。
浙公網(wǎng)安備 33010602011771號(hào)