2015-04-28 1 views
2

У меня очень простое консольное приложение Windows, которое сначала создает поток для обработки ввода на stdin. Он использует CreateThread() в main(), чтобы создать поток, и первое, что делает поток, - это позвонить getchar() и заблокировать, ожидая.Почему заблокированный IO в другом потоке не позволяет CreateWindowEx() возвращать

Затем main() регистрирует класс окна с использованием RegisterClass() и вызывает CreateWindowEx() для создания невидимого окна сообщения.

НО CreateWindowEx() не возвращается.

Если я удалю getchar() в нити и замените его while (1) Sleep(1000);, все будет работать.

Если я добавлю Sleep(1000); в начало функции потока, вызов CreateWindowEx() завершается успешно, но тогда вводе/выводе в потоке перестает работать (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 (поскольку это влияет на обратный вызов THREAD_ATTACH) ,

Попробуйте сделать это «правильно», только создавая вызовы CRT по потокам, начинающимся с _beginthreadex. (Один из способов - использовать CreateThread, а затем использовать ReadConsole в рабочей нитке вместо getchar, а другой - использовать _beginthreadex вместо CreateThread).

+0

Спасибо за понимание, Бен. Я попытался быстро изменить код потока, чтобы использовать _beginthread(), и это не помогло. Он все еще висит внутри CreateWindowEx(). Я также переделал работу с ReadConsole(), но это оказалось сложной задачей. Я не уверен, почему он пока не работает. – Nicholas

+0

Я не мог заставить это работать, используя _beginthreadex(), но, наконец, смог заставить его работать, используя ReadFile() и WriteFile(), чтобы заменить все функции stdio. Спасибо, Бен! – Nicholas

+0

@ Николас: Пожалуйста. И да, 'ReadFile' - хороший выбор для ввода-вывода, включая консольный ввод-вывод, если вас интересуют только данные символа. 'ReadConsole' предоставляет персональные данные (клавиатура и буфер обмена) плюс мышь. –