2015-04-28 192 views
2

我有一個非常簡單的Windows控制檯應用程序,它首先創建一個線程來處理stdin上的輸入。它使用CreateThread()中的main()來創建線程,線程所做的第一件事情是調用getchar()並阻止,等待。爲什麼在另一個線程中阻塞的IO阻止CreateWindowEx()返回

然後main()使用RegisterClass()註冊一個窗口類並調用CreateWindowEx()來創建一個不可見的消息窗口。

但是CreateWindowEx()永不退貨。

如果我刪除線程中的getchar()並將其替換爲while (1) Sleep(1000);,則一切正常。

如果我將Sleep(1000);添加到線程函數的開頭,CreateWindowEx()調用成功,但線程中的I/O停止工作(getchar()不返回)。

爲什麼被阻塞的第二個線程會干擾第一個線程?

+0

你的窗口過程發生了什麼?你收到了「WM_NC_CREATE」嗎? –

+0

窗口過程只是調用DefWindowProc(),除非它是WM_USER消息,在這種情況下,它會將該消息記錄到文件中。如果我不在線程中調用getchar(),這將起作用。我不知道WM_NC_CREATE是否正在發送給它。 – Nicholas

+2

你能提供[一個MCVE](http://stackoverflow.com/help/mcve)嗎? –

回答

2

C運行時庫不正式支持從CreateThread生成的線程調用。您應該使用CRT包裝功能,例如_beginthreadex,它可以在新線程上正確配置CRT線程本地狀態。

實際上,即使違反了規則,CRT也會竭盡全力讓其工作,但細節取決於您是否靜態或動態地與CRT連接(因爲這會影響是否存在回調THREAD_ATTACH) 。

嘗試通過僅在_beginthreadex開始的線程上進行CRT調用來做到「正確」。 (一種方法是繼續使用CreateThread,然後在工作線程中使用ReadConsole而不是getchar,另一種方法是使用_beginthreadex而不是CreateThread)。

+0

謝謝你的見解,本。我試着快速改變線程代碼來使用_beginthread(),但它沒有什麼區別。它仍然掛在CreateWindowEx()中。我還修改了ReadConsole()來代替工作,但事實證明這很具有挑戰性。我不確定它爲什麼還沒有工作。 – Nicholas

+0

我無法使用_beginthreadex()獲得此工作,但最終能夠通過使用ReadFile()和WriteFile()來替換所有stdio函數來使其工作。謝謝Ben! – Nicholas

+0

@尼古拉斯:不客氣。是的,如果你只對字符數據感興趣,'ReadFile'對I/O來說是一個不錯的選擇,包括控制檯I/O。 'ReadConsole'提供字符數據(鍵盤和剪貼板)以及鼠標。 –