线程模式是微软的COM基础中的极其重要的概念.一定要吃透!
初始一个STA套间实际上是相当于开了一个消息窗口,所有调用经此窗口过程调度到组件内.

[STAThread]

可以理解成CoInitialize(NULL); 
初始一个STA套间实际上是相当于开了一个消息窗口,所有调用经此窗口过程调度到组件内.
[MTAThread]
可以理解成CoInitializeEx(NULL,COINIT_MULTITHREADED )
这经常是一个对初入com大门的人来说,有一定难度但必须过的一道关.

概念

线程模型的存在就是线程规则的不同导致的,而所谓的线程规则就只有两个:代码是线程安全的或不安全的,即代码访问公共数据时会或不会发生冲突。
由于线程模型只是个模型,概念上的,因此可以违背它,不过就不能获得COM提供的自动同步(序列化)调用的好处了。

1.线程模型是干嘛用的?
解决”多个线程”“同时”调用你的COM组件的并发控制。客户没有你的COM的源代码,它不知道你的组件是怎么写的,是不是线程安全的(是否用CriticalSection或Mutex保护了临界资源),所以要有一种机制来声明组件的线程安全性,你开发时指定了组件的线程模型,客户端一看,哦,它就知道该怎么写调用的代码。
2.啥时候用操心线程模型?
全看客户端是单线程还是多线程,单线程不用操心,怎么调都没事,多线程就来事了,跨线程调用时就要考虑。
3.线程模型的一堆概念都是哪跟哪啊?
首先一分为二:客户端和组件。客户端用CoInitializeEx进入一种套间,Apartment、Free是指的客户端进入的套间种类;组件要向注册表写入自己兼容什么样的客户端套间,是Apartment,还是Free,还是两种都兼容(Both)。
4.客户端的线程套间和组件的不一致了咋办,难道我调个COM组件还得查注册表看看兼容什么线程模型?
不一致时以组件为主。客户端建的是Apartment,组件兼容Free,那COM背地里会在客户端建一个Free套间,把组件放进去。反之,会建一个Apartment套间把组件放进去。总之以组件为主,这是关键,只有这样,你才不用关心组件的线程安全性,COM服务替你在后台办妥了。
5.听说过列集这个名词,是什么啊,啥时候用?
记死了,跨线程调用组件就得列集,没的商量。传出接口的线程列集,使用接口的线程散列。列集说白了就是不让你直接调用组件的接口,而是调用接口的代理。COM服务在中间插一杠子,干啥,实现COM线程安全那一揽子事呗,它不拦截你的调用它怎么实现啊,所以就给你个代理,所以就列集了呗。

内容来源:https://www.cxybb.com/article/crybird/80808960

COM库的规定

关于多线程问题方面,COM库做出了如下规则(不是COM标准,是COM库为了简化多线程编程中对组件的调用而制定的):
1.  COM库提供两种套间,单线程套间和多线程套间,COM组件的编写者最好提供对应的属性(后面会提到),COM组件的使用者要在套间里创建和调用组件。
2.  COM库对所有的调用进行参数调整(如果需要),不管是对进程内服务器的调用,还是对进程外服务器的调用。
3.  线程内调用、跨线程调用、跨进程调用都用统一的方式。需要用代理的会用代理。
个人理解COM套间线程模型就是一组访问控制规则,规范了线程如何访问套件对象。STA表示被标注STA的线程只能单独访问套间对象。MTA 表示被标注为MTA线程可以和其他MTA线程一起访问套间对象。

COM中的线程

Win32中的线程,典型的Win32程序具有两种不同类型的线程:用户界面线程和工作者线程。用户界面线程是同一个或者多个窗口关联着的,这些线程具有自己的消息循环,以便能对用户输入做出反应。工作者线程用于后台处理,它们没有任何窗口与之相关联,通常也没有消息循环。
    COM中使用的线程类型与Win32的两种类型的线程是相同的,只不过换了不同的名称而已。在COM中与Win32中的用户界面线程相对应是“套间线程”,而与工作者线程相对应的是自由线程。
    既然COM线程与Win32线程并没有什么差别,那么为什么COM还需要定义自己的线程呢?其原因在于参数调整与线程同步。
5.1 套间线程: 当线程调用CoInitializeEx时,使用参数 COINIT_APARTMENTTHREADED 时,此时这个线程就被称为是套间线程。
对于套间线程我们可以将其想象成一个用户界面线程。
① 我们知道一个用户界面线程将拥有所有在该线程中创建的窗口,同理一个套间线程将拥有所有它所创建的组件;

一个套间中组件只能由相应的套间线程来调用。如果某个线程给另外一个线程所拥有的窗口发送一条消息(SendMessage函数可以向不同线程中创建的窗口发送消息),Windows将把此消息放到那个窗口所在的线程消息队列中。窗口的消息循环将在创建此窗口的线程中执行。当消息循环取出一条消息并调用窗口过程时,此窗口过程也在,创建窗口的线程上运行。对于套间中的组件亦是如此,假设另一个线程调用一个套间中的某个组件的方法,COM库将把此请求放到套间的队列中。消息循环将取出此调用请求并在套间线程上执行相应的方法。通过这种消息调用机制,保证了套间中的组件只在相应的套间线程中被调用,也就是说不会出现多个线程并发访问这个组件的情况,因此组件就不需要考虑线程同步的问题了。
也就是说如果在某个时刻,一个线程是套间线程,则COM库将完成对组件的同步调用,实现方法:使用窗口的消息循环机制,将不同线程中的函数调用,封装成消息发送到套间线程,然后再套间线程中执行代码,从而保证,组件不会被并发访问。
5.2 自由线程:当线程调用CoInitializeEx时,使用参数 COINIT_MULTITHREADED 时,此时这个线程就被称为是自由线程。

5.3 一个线程不会固定的只是 套间线程或是 自由线程,因为一个线程可以多次进入不同的套间,当该线程进入的是单线程套间是此时这个线程就是套间线程,当该线程进入多线程套间时,这个线程就是自由线程。

COM将在套间线程上同步对组件的调用。对于由自由线程创建的组件的调用,COM不能使之同步。若某个组件是由自由线程创建的,则任意线程均可在任意时候调用它。此时组件开发者应保证对组件访问的同步。也就是说,此时组件应是线程安全的。实际上使用自由线程,同步的工作将由 COM移至组件本身。
此时由于COM并不同步对组件的调用,因此自由线程不需要消息循环。由自由线程创建的组件将是一个可以供任意线程访问的组件。此时创建此组件的线程并不拥有此组件,此组件将被所有的线程共享,并可供所的线程自由访问。

5.4 单线程套间(single-threaded apartments)和多线程套间(multithreaded apartments)

前面我们描述的套间线程和自由线程,我们COM线程的角度来讨论的,现在我们从COM套间的角度来看看COM线程,其实如果一个线程某个时刻进入了一个COM单线程套间我们就称此线程此时是一个套间线程,如果一个线程在某个时刻进入了一个COM多线程套间我们就称此线程此时是一个自由线程。

【C#】COM线程模型-套间 ApartmentState的更多相关文章

  1. COM线程模型 套间概念

    COM线程模型 套间概念 1) 单线程套间.线程是COM主线程,初始化COM库的进程的第一个线程.即使从其他线程访问COM组件,也不需要手工同步,COM库已经实现了同步.寓所线程里有个消息处理循环来处 ...

  2. WPF的线程模型

    原文:WPF的线程模型 WPF的线程模型            周银辉 谈到多线程,很多人对其可能都不太有好感,觉得麻烦与易出错.所以我们不排除有这样的情况:假设我对“多线程”.“异步”这些字眼潜意识 ...

  3. 看我是如何处理自定义线程模型---java

    看过我之前文章的园友可能知道我是做游戏开发,我的很多思路和出发点是按照游戏思路来处理的,所以和web的话可能会有冲突,不相符合. 来说说为啥我要自定义线程模型呢? 按照我做的mmorpg或者mmoar ...

  4. HBase的Write Ahead Log (WAL) —— 整体架构、线程模型

    解决的问题 HBase的Write Ahead Log (WAL)提供了一种高并发.持久化的日志保存与回放机制.每一个业务数据的写入操作(PUT / DELETE)执行前,都会记账在WAL中. 如果出 ...

  5. Netty学习三:线程模型

    1 Proactor和Reactor Proactor和Reactor是两种经典的多路复用I/O模型,主要用于在高并发.高吞吐量的环境中进行I/O处理. I/O多路复用机制都依赖于一个事件分发器,事件 ...

  6. Mina、Netty、Twisted一起学(十):线程模型

    要想开发一个高性能的TCP服务器,熟悉所使用框架的线程模型非常重要.MINA.Netty.Twisted本身都是高性能的网络框架,如果再搭配上高效率的代码,才能实现一个高大上的服务器.但是如果不了解它 ...

  7. WPF QuickStart系列之线程模型(Thread Model)

    这篇博客将介绍WPF中的线程模型. 首先我们先来看一个例子,用来计算一定范围内的素数个数. XAML: <Grid> <Grid.RowDefinitions> <Row ...

  8. servlet的生命周期与运行时的线程模型

    第 14 章 生命周期 注意 讲一下servlet的生命周期与运行时的线程模型,对了解servlet的运行原理有所帮助,这样才能避免一些有冲突的设计. 如果你不满足以下任一条件,请继续阅读,否则请跳过 ...

  9. eventloop & actor模式 & Java线程模型演进 & Netty线程模型 总结

    eventloop的基本概念可以参考:http://www.ruanyifeng.com/blog/2013/10/event_loop.html Eventloop指的是独立于主线程的一条线程,专门 ...

随机推荐

  1. Spring 官宣发布 Spring Boot 3.0 第一个里程碑 M1,从 Java 8 提升到 Java 17!

    Spring官方于2022年1月20日发布Spring Boot 3.0.0-M1版本,预示开启了Spring Boot 3.0的里程碑,相信这是通往下一代Spring框架的激动人心的旅程. 接下来一 ...

  2. VS2017:win32项目与win32控制台应用程序的转换方法

    原文:https://www.cnblogs.com/asuser/articles/12297251.html 刚开始使用VS2017新建项目工程时,有时把应用类型的工程建成控制台类型的工程,在编译 ...

  3. Codeforces Round #746 Div. 2

    掉分快乐qwq C题代码以及分析(在注释里) /* * @Author: Nan97 * @Date: 2021-10-04 22:37:18 * @Last Modified by: Nan97 * ...

  4. Atcoder ARC-068

    A 不难发现从 \(5\) 开始一直往 \(6\) 转再转回来是最优的,直接模拟即可. B 不难发现可以将多余部分直接贪心消去,最后必然会剩下两个或 \(1\) 个多余的数. 如果剩下两个,此时多余的 ...

  5. Sleep_Yield_Join

    名称解释 Sleep:意思就是睡眠,当前线程暂停一段时间让给别的线程去运行;Sleep是怎么复活的?由你的睡眠时间而定,等睡眠到规定的时间自动复活. Yield:就是当前线程正在执行的时候停止下来进入 ...

  6. JDBC工具包commons-dbutils的基本介绍

    感谢原文作者:simonXi-tech 原文链接:https://blog.csdn.net/simonforfuture/article/details/90480147 更多请查阅在线API文档: ...

  7. navicat连接mysql报错1251解决方案

    感谢原文作者:XDMFC 原文链接:https://blog.csdn.net/xdmfc/article/details/80263215 问题描述 今天下了个 MySQL8.0,发现Navicat ...

  8. Android基本控件Spinner的简单使用【转】

    Android基本控件Spinner的简单使用 感谢大佬:https://blog.csdn.net/bingocoder/article/details/80469939 学习过了Textview, ...

  9. java基础之抽象类的介绍

    抽象类的特点: 1.当方法只有声明没有具体实现的时候,需要用abstract修饰符修饰.抽象方法必须定义在抽象类当中,所以抽象类也需要用abstract修饰 2.抽象类不可以被实例化,为什么呢?   ...

  10. UITextFIeld的输入格式问题 ----W.P

    ---恢复内容开始--- 1.银行卡的输入格式,四个数字,一个空格. 2.金额的输入格式限制,不能以"."开头,"."后精确两位. 注意:第三方输入软件(百度, ...