Відповіді:
Модель різьблення COM називається "квартирною" моделлю, де контекст виконання ініціалізованих об'єктів COM пов'язаний або з однією ниткою (Single Thread Apartment), або з багатьма потоками (Multi Thread Apartment). У цій моделі об’єкт COM, щойно ініціалізований у квартирі, є частиною цієї квартири протягом часу її виконання.
Модель STA використовується для об'єктів COM, які не є безпечними для потоків. Це означає, що вони не обробляють власну синхронізацію. Загальне використання цього компонента - інтерфейс користувача. Отже, якщо інший потік повинен взаємодіяти з об'єктом (наприклад, натисканням кнопки у формі), то повідомлення буде розміщено на потоці STA. Прикладом цього є система перекачування повідомлень Windows.
Якщо об'єкт COM може працювати з власною синхронізацією, то модель MTA може використовуватися там, де дозволено взаємодіяти з об'єктом декількох потоків без маршальованих викликів.
Все зводиться до того, як обробляються дзвінки до об'єктів та який захист їм потрібен. Об'єкти COM можуть запитувати час виконання, щоб захистити їх від виклику кількома потоками одночасно; ті, які не можуть бути викликані одночасно з різних потоків, тому їм доводиться захищати власні дані.
Крім того, також потрібно, щоб час виконання не дозволяв виклику об'єкта COM блокувати користувальницький інтерфейс, якщо виклик здійснюється з потоку користувальницького інтерфейсу.
Квартира є місце для об'єктів , щоб жити, і вони містять один або кілька потоків. Квартира визначає, що відбувається, коли здійснюються дзвінки. Дзвінки на об'єкти в квартирі будуть отримані та оброблені на будь-якій нитці в цій квартирі, за винятком того, що виклик потоком, що вже знаходиться у правій квартирі, обробляється сам (тобто прямий дзвінок на об’єкт).
Нитки можуть бути або в однонитковій квартирі (в такому випадку вони є єдиною ниткою в цій квартирі), або в багатонитковій квартирі. Вони задають, який, коли нитка ініціалізує COM для цього потоку.
STA - це насамперед для сумісності з інтерфейсом користувача, який прив’язаний до конкретної нитки. ДПА отримує сповіщення про дзвінки на обробку, отримуючи віконне повідомлення до прихованого вікна; коли робить вихідний дзвінок, він запускає модальний цикл повідомлень, щоб запобігти обробці інших віконних повідомлень. Ви можете вказати фільтр повідомлень, який потрібно викликати, щоб ваша програма могла відповідати на інші повідомлення.
На противагу цьому всі потоки MTA поділяють одну MTA для цього процесу. COM може запустити новий робочий потік для обробки вхідного дзвінка, якщо немає потоків, до межі пулу. Нитки, що здійснюють вихідні дзвінки, просто блокуються.
Для простоти ми розглянемо лише об’єкти, реалізовані в DLL, які рекламують у реєстрі те, що вони підтримують, встановлюючи ThreadingModel
значення для класу свого класу. Є чотири варіанти:
ThreadingModel
значення немає) Об'єкт створюється на головному потоці інтерфейсу користувача, і всі виклики перенесені в цей потік. Фабрика класів буде викликана лише на цій темі.Apartment
. Це вказує на те, що клас може працювати на будь-якому потоці з однопоточним режимом. Якщо потік, який його створює, є потоком STA, об'єкт буде запускатися на цьому потоці, інакше він буде створений в основній STA - якщо немає основної STA, для нього буде створено нитку STA. (Це означає, що потоки MTA, які створюють об'єкти Квартири, будуть здійснювати зйомки всіх викликів на інший потік.) Фабрику класів можна викликати одночасно кількома потоками STA, тому він повинен захищати свої внутрішні дані від цього.Free
. Це вказує на клас, призначений для запуску в MTA. Він завжди завантажується в MTA, навіть якщо він створений потоком STA, що знову означає, що виклики потоку STA будуть скасовані. Це тому, що Free
об'єкт, як правило, пишеться з очікуванням, що він може блокувати.Both
. Ці класи є гнучкими та завантажуються в тій квартирі, з якої вони створені. Вони повинні бути написані таким чином, щоб вони відповідали обом наборам вимог: проте вони повинні захищати свій внутрішній стан від одночасних викликів, якщо вони завантажені в MTA, але не повинні блокувати, якщо вони завантажені в STA.З .NET Framework в основному просто використовуйте [STAThread]
будь-який потік, що створює інтерфейс користувача. Робочі потоки повинні використовувати MTA, за винятком випадків, коли вони будуть використовувати Apartment
COM-компоненти, позначені COM, і в цьому випадку використовувати STA, щоб уникнути неполадки накладних витрат і масштабованості, якщо один і той же компонент викликається з декількох потоків (оскільки кожен потік повинен буде чекати на компонент по черзі). Навколо набагато простіше, якщо ви використовуєте окремий COM-об'єкт на потік, будь то компонент в STA або MTA.
Я вважаю, що існуючі пояснення є занадто гоблеми. Ось моє пояснення простою англійською мовою:
STA: Якщо потік створює об'єкт COM, встановлений на STA (під час виклику CoCreateXXX ви можете передати прапор, який встановлює об'єкт COM в режим STA), тоді лише ця нитка може отримати доступ до цього об'єкта COM (ось що означає STA - Single Threaded Apartment ), інший потік, який намагається викликати методи цього об'єкта COM, під кришкою мовчки перетворюється на доставку повідомлень до потоку, який створює (володіє) об'єктом COM. Це дуже схоже на те, що тільки потік, який створив елемент управління інтерфейсом, може отримати доступ до нього безпосередньо. І цей механізм покликаний запобігати складним операціям блокування / розблокування.
MTA: Якщо потік створює COM-об'єкт, встановлений на MTA, то майже кожен потік може безпосередньо викликати методи на ньому.
Це в основному суть цього. Хоча технічно є деякі деталі, які я не згадував, як-от в абзаці "STA", потік розробника повинен бути STA. Але це майже все, що ви повинні знати, щоб зрозуміти STA / MTA / NA.
STA (Single Threeded Apartment) - це в основному концепція того, що лише один потік одночасно взаємодіє з вашим кодом. Дзвінки у вашу квартиру скасовуються за допомогою вікон повідомлень (використовуючи невидиме) вікно. Це дозволяє чергувати дзвінки і чекати завершення операцій.
MTA (Multi-Threaded Apartment) - це те, що багато потоків можуть працювати одночасно, і навантаження на вас, як розробника, керувати безпекою потоку.
Є багато іншого, щоб дізнатись про нитки моделей в COM, але якщо у вас виникають проблеми з розумінням того, що вони є, я б сказав, що розуміння того, що таке STA та як це працює, було б найкращим місцем для початку, оскільки більшість об'єктів COM - це STA.
Нитка квартири, якщо нитка живе в тій же квартирі, що і об'єкт, який вона використовує, то це квартирна нитка. Я думаю, що це лише концепція COM, оскільки це лише спосіб говорити про об'єкти та теми, з якими вони взаємодіють ...
Кожен EXE, у якому розміщені елементи керування COM або OLE, визначає стан квартири. Стан квартири за замовчуванням є STA (і для більшості програм має бути STA).
ДПА - Усі засоби управління OLE за потребою повинні жити в ДПА. STA означає, що вашим COM-об'єктом потрібно завжди керувати потоком інтерфейсу і не може передаватися іншим потокам (подібно до будь-якого елемента інтерфейсу в MFC). Однак у вашій програмі все ще може бути багато потоків.
MTA - Ви можете маніпулювати об'єктом COM на будь-якому потоці програми.
Як я розумію, "Квартира" використовується для захисту об'єктів COM від проблем із багатопотоковою резьбою.
Якщо об'єкт COM не є безпечним для потоків, він повинен оголосити його як об'єкт STA. Тоді до нього може отримати доступ лише нитка, яка її створює. Нитка створення повинна заявляти про себе як потік STA. Під кришкою нитка зберігає інформацію STA у своєму TLS (Thread Local Storage). Ми називаємо цю поведінку такою, що нитка заходить у квартиру ДПА. Коли інші потоки хочуть отримати доступ до цього об'єкта COM, він повинен маршалити доступ до потоку створення. В основному, потік створення використовує механізм повідомлень для обробки вбудованих викликів.
Якщо об'єкт COM захищений потоком, він повинен оголосити його як об'єкт MTA. До об'єкта MTA можна отримати доступ до кількох потоків.
Код, який викликає кодові об'єкти COM (наприклад, для читання файлів власних даних), може працювати чудово в користувальницькому інтерфейсі, але загадково висить у сервісі. Причина полягає в тому, що станом на .Net 2.0 користувальницькі інтерфейси приймають STA (безпечно для потоків), а служби передбачають MTA (до цього послуги передбачали STA). Необхідність створення потоку STA для кожного COM-дзвінка в службі може додати значні накладні витрати.