Основной поток приложения с графическим интерфейсом - это поток STA, Single Threaded Apartment.Обратите внимание на атрибут [STAThread] в методе Main () вашей программы.STA - это термин COM, он предоставляет гостеприимный дом для компонентов, которые в основном не поддерживают потоки, что позволяет вызывать их из рабочего потока.COM все еще очень жив в приложениях .NET.Перетаскивание, буфер обмена, диалоги оболочки, такие как OpenFileDialog, и общие элементы управления, такие как WebBrowser, являются однопоточными COM-объектами.STA является жестким требованием для потоков пользовательского интерфейса.
Поведенческий контракт для потока STA заключается в том, что он должен прокачать цикл сообщений и не может блокироваться.Блокировка, скорее всего, приведет к взаимоблокировке, поскольку она не позволяет выполнить маршалинг для этих COM-компонентов с многопоточным соединением.Вы блокируете поток с помощью оператора lock .
CLR очень хорошо знает об этом требовании и что-то с ним делает.Блокирующие вызовы, такие как Monitor.Enter (), WaitHandle.WaitOne / Any () или Thread.Join () прокачивают цикл обработки сообщений.Тип собственного API-интерфейса Windows, который делает это, MsgWaitForMultipleObjects (). Этот цикл обработки сообщений отправляет сообщения Windows для поддержания работоспособности STA, включая сообщения рисования.Конечно, это может вызвать проблемы с повторным входом, Paint не должен быть проблемой.
В этом посте Chris Brumme есть хорошая справочная информация .
Может быть, этовсе звучит как звонок, вы, вероятно, не можете не заметить, что это звучит очень похоже на приложение, вызывающее Application.DoEvents ().Вероятно, самый страшный метод для решения проблем зависания пользовательского интерфейса.Это довольно точная ментальная модель того, что происходит внутри, DoEvents () также прокачивает цикл сообщений.Единственное отличие состоит в том, что эквивалент CLR немного более избирателен в отношении того, какие сообщения он разрешает отправлять, он фильтрует их.В отличие от DoEvents (), который отправляет все.К сожалению, ни пост Брамме, ни источник SSCLI20 не достаточно детализированы, чтобы точно знать, что отправляется, реальная функция CLR, которая делает это, недоступна в источнике и слишком велика для декомпиляции.Но ясно видно, что он не фильтрует WM_PAINT.Он будет отфильтровывать настоящих создателей проблемы, вводить уведомления о событиях наподобие того, который позволяет пользователю закрыть окно или нажать кнопку.
Функция, а не ошибка.Избегайте головных болей повторного входа, сняв блокировку и полагаясь на обратные вызовы с маршалингом.BackgroundWorker.RunWorkerCompleted является классическим примером.