2017-02-15 11 views
2

Этот вопрос связан с популярнейших комментарием this question:C# - Почему Control. (Начало) Вызывает необходимость, хотя пользовательский интерфейс работает в STAThread?

Модель STA используется для COM-объектов, которые не являются поточно. Это означает, что они не выполняют свою собственную синхронизацию. Общим использованием этого является компонент пользовательского интерфейса. Поэтому, если другой поток должен взаимодействовать с объектом (например, нажимать кнопку в форме), тогда сообщение сортируется по потоку STA. Примером этого является система обработки сообщений в виде окон.

Так следующий пример путает меня немного ..

Главная помечается [STAThread].

[STAThread] 
static void Main() 
{ 
    Application.EnableVisualStyles(); 
    Application.SetCompatibleTextRenderingDefault(false); 
    Application.Run(new Form1()); 
} 

я предполагая, что, поскольку Form1 работает в STAThread, каждое сообщение в UI-компонент, который посылается от другой нити ранжированы на резьбу STA.

Поэтому я ожидал, что вызов, как это будет работать:

public Form1() 
{ 
    InitializeComponent(); 

    Thread t = new Thread(() => { this.label1.Text = "test"; }); 
    t.IsBackground = true; 
    t.Start(); 
} 

Как обсуждалось во многих других должностей, он не будет работать. Thread t ... должен быть заменен чем-то вроде Thread t = new Thread(()=> { this.label1.Invoke((Action)(() => { this.label1.Text = "test"; })); });, чтобы исправить это, но имея в виду, что STA должен marshall this.label1.Text = "test"; на mainthread, почему я все еще получаю недопустимую ошибку доступа к перекрестным потокам?

Edit решаемая:

Принято Ответ:

[STAThread][MTAThread]) относятся только к работе с COM Interop.

Поскольку Label-Object, кажется, только оболочкой для управления Win32, это не COM-объект (как ошибочно ожидали от меня из-за BLOCKQUOTE в начале этого вопроса), и поэтому требует не быть распределенным. Существуют проверки вызовов из других потоков внутри обертки, но маршаллинг через (Begin) Invoke должен выполняться разработчиком.

Предстоящий вопрос, конечно же: как можно модифицировать обертку, так что это делается автоматически и с минимальной совместимостью .. но это другая тема, я думаю.

+0

* «что STA должно быть маршалом» * Должно ли? Темы - это контекст исполнения, они не имеют никакой логики или не знают, что такое форма, или знают, что эта вещь в структуре имеет сходство нитей, и это не так. Это твоя работа. – Will

+0

@WA [STA] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms680112 (v = vs.85) .aspx) - это не сам поток. – ChrisG

+0

Это поточный парадигма. Акцент на темы. – Will

ответ

1

По умолчанию объекты .net не имеют какого-либо многопоточного маршалинга.

[STAThread][MTAThread]) относятся только к работе с COM-взаимодействием. Как правило, эти атрибуты инструктируют, как инициализировать поток через вызов CoInitializeEx.Таким образом, реальное сортирование произойдет только при доступе к COM-объектам, и это будет сделано подсистемой COM, а не .net.

UI - это другой зверь. На самом деле большинство элементов управления Win32, которые используются под капотом, являются потокобезопасными (потому что они основаны на парадигме сообщений), но обертки .net вокруг них не являются. Таким образом, чтобы предотвратить противоречивое состояние при работе с пользовательским интерфейсом, все классы WinForms имеют специальные проверки для доступа к ним из разных потоков.

Подводя итог, при доступе к классам WinForms из разных потоков не происходит сортировки по умолчанию, существует только простая проверка потока, и именно поэтому вы должны делать маршалинг самостоятельно.

3

STA обозначает single threaded apartments, используемый для обеспечения того, чтобы один поток мог одновременно получать доступ к компоненту COM. Исключение, которое вы получаете, связано не с синхронизацией COM с несколькими потоками, а с доступом к элементу управления в потоке, на котором он не создан.

Элемент управления меткой создается в потоке графического интерфейса пользователя и должен быть доступ к потоку, создаваемому i.e. Вы пытаетесь получить к нему доступ в потоке без GUI, поэтому вы получаете исключение перекрестного потока. Метод Invoke будет обращаться к потоку Label on GUI, и вы не получите исключение перекрестного потока.

Комментарий OP

в этом примере - ГНА будет сортировочных каждый вызов к UI-компонент из другого потока на UI-нить, так что фактически выполняется на UI-нить и, следовательно, больше нет поперечной резьбы. Или сортирует работу по-другому?

Marshaling - это механизм, с помощью которого объект, доступный для одной квартиры, может быть доступен для другой квартиры, reference. В COM-компонентах при вызове метода вызов выполняется исходящей квартирой, и результаты возвращаются отправителю вызова. С другой стороны, для не COM-компонентов квартира STA не будет действовать. Ограничение доступа к объектам графического интерфейса пользователя в потоке, создаваемом им .net для не COM-компонентов, таких как Label, Button и т. Д., Необходимо обрабатывать с помощью таких методов, как Invoke, например, при обращении к потоку, отличному от потока графического интерфейса.

Marshaling Поскольку правила квартиры типовых объектов является то, что они могут быть доступны только из потока, на котором они были созданы, что вам нужно сделать некоторую дополнительную работу, если вы хотите получить доступ к ним из другого потока: Вы должны hire a lackey , COM называет это «прокси». Когда вы вызываете метод на прокси-объекте, вызов перенаправляется обратно в исходную квартиру, метод выполняется на его исходной квартире, а затем результаты перенаправляются обратно на исходный вызывающий. (И если любой из параметров этого метода сами являются объектами, то COM тоже должен создавать прокси для этих объектов!) Маршалинг - это механизм для создания прокси.

STAThreadAttribute

модели COM пронизывающие применимы только к приложениям, использующим COM Interop. Модель с резьбой COM может быть установлена ​​в однопоточную квартиру или квартиру многопоточную квартиру. Поток приложения инициализируется только для COM-взаимодействия, если поток фактически выполняет вызов COM-компонента . Если COM-взаимодействие не используется, то поток не инициализируется , а атрибут STAThreadAttribute, если он присутствует, не влияет.

How to: Make Thread-Safe Calls to Windows Forms Controls

Доступ к Windows Forms управления не по своей сути поточно. Если у вас есть два или более потока, управляющих состоянием элемента управления, то можно отключить управление в несогласованном состоянии . Другие возможны связанные с потоком ошибки, такие как условия гонки и взаимоблокировки. Важно убедиться, что доступ к вашим элементам управления выполняется поточно-безопасным способом. Небезопасно вызывать элемент управления с нитью, отличной от той, которая создала элемент управления, без использования метода Invoke . Ниже приведен пример вызова, который не является безопасным потоком .

+0

Это также улучшило бы ответ, если бы вы могли объяснить * почему * доступ к элементу управления из потока, который он не создал, был бы проблемой. –

+0

Спасибо за ваш ответ! Я думал, что в этом примере STA сортирует каждый вызов UI-компонента из другого потока в UI-Thread, поэтому он фактически выполняется в UI-Thread и, следовательно, больше не имеет сквозной потоковой передачи. Или сортирует работу по-другому? – ChrisG

+0

@ChrisG, см. Мой обновленный ответ. – Adil

 Смежные вопросы

  • Нет связанных вопросов^_^