Я только что исправил ошибку:
_Thread.SetApartmentState(ApartmentState.STA);
Теперь я хочу понять, что это значит и почему работает!
.net
multithreading
Benjol
источник
источник
Ответы:
COM - прародитель .NET. У них были довольно высокие цели. Одна из вещей, которые COM делает, но полностью пропускает .NET, - это обеспечение гарантии многопоточности для класса. СОМ-класс может публиковать требования к потокам. И инфраструктура COM обеспечивает выполнение этих требований.
Это полностью отсутствует в .NET. Вы можете использовать объект Queue <>, например, в нескольких потоках, но если вы не заблокируете его должным образом, в вашем коде будет неприятная ошибка, которую очень трудно диагностировать.
Точные детали потоковой передачи COM слишком велики, чтобы поместиться в посте. Я остановлюсь на специфике вашего вопроса. Поток, который создает объекты COM, должен сообщить COM, какую поддержку он хочет предоставить классам COM, которые имеют ограниченные параметры потоковой передачи. Подавляющее большинство этих классов поддерживают только так называемые потоки квартир, их методы интерфейса могут безопасно вызываться только из того же потока, который создал экземпляр. Другими словами, они объявляют: «Я вообще не поддерживаю потоки, пожалуйста, позаботьтесь о том, чтобы никогда не звонить мне из неправильного потока». Даже если клиентский код на самом деле делает вызов из другого потока.
Существует два вида: STA (однопоточная квартира) и MTA. Он указывается в вызове CoInitializeEx (), функции, которая должна вызываться любым потоком, который что-либо делает с COM. CLR выполняет этот вызов автоматически всякий раз, когда запускает поток. Для основного потока запуска вашей программы он получает значение, передаваемое из атрибута [STAThread] или [MTAThread] в вашем методе Main (). По умолчанию - MTA. Для потоков, которые вы создаете самостоятельно, это определяется вашим вызовом SetApartmentState (). По умолчанию - MTA. Потоки Threadpool всегда являются MTA и не могут быть изменены.
В Windows есть много кода, для которого требуется STA. Известные примеры, которые вы бы использовали сами, - это буфер обмена, Drag + Drop и диалоги оболочки (например, OpenFileDialog). И много кода, который вы не видите, например программы автоматизации пользовательского интерфейса и хуки для наблюдения за сообщениями. Ни один из этих кодов не должен быть потокобезопасным, его автору будет очень трудно сделать его безопасным, не зная, в какой программе он используется. Соответственно, поток пользовательского интерфейса проекта WPF или Windows Forms всегда должен быть STA для поддержки такого кода, как и любой поток, создающий окно.
Однако обещание, которое вы даете COM, что ваш поток является STA , требует от вас соблюдения контракта однопоточного апартамента. Они довольно жесткие, и при разрыве контракта бывает сложно диагностировать проблему. Требования состоят в том, что вы никогда не блокируете поток на какое-либо время и вы накачиваете цикл сообщений. Последнее требование выполняется потоком пользовательского интерфейса WPF или Winforms, но вам нужно будет позаботиться об этом самостоятельно, если вы создадите свой собственный поток STA. Обычная диагностика разрыва контракта - это тупик.
В CLR есть довольно много встроенной поддержки для поддержки этих требований, кстати, помогая вам избежать неприятностей. Оператор блокировки и методы WaitOne () накачивают цикл сообщений, когда он блокируется в потоке STA. Однако это касается только требования никогда не блокировать, вам все равно нужно создать свой собственный цикл сообщений. Application.Run () как в WPF, так и в Winforms.
Ранее я давал ответ, содержащий более подробную информацию о важности наличия цикла сообщений для обеспечения комфорта COM. Вы найдете сообщение здесь .
источник