















对于SynchronizationContext不了解,可以先看下我之前的两篇文章:
线程之间的通讯---SynchronizationContext
奇妙的SynchronizationContext
首先说下关于一些线程的基础东西,这样有利于更好的理解。
1、STA、MTA和Apartments
在16 bit Windows的时代,只有一个线程存在,所以一切都是那么的简单,可是,随着时代的进步,出现了Win32,这时出现了混乱,为了维持次序,Apartments出现了(Apartments是COM为了简化对象对多线程的支持而推出的一套机制,用于指定线程和COM对象的多线程特性,并且对不同特性的套间之间的调用提供同步支持,保证不同多线程特性的对象之间可以互相正确调用而不会引入同步问题),线程的执行必须在Apartments中,也就是线程对COM对象执行多线程调用,还是单线程调用。STA表示只支持单线程调用,MTA表示支持多线程调用。
在一个进程中可以有多个STA单元,一个MTA单元。一个STA单元中只能有一个线程,而MTA单元中允许有多个线程。
对于STA和MTA,我们把它用于标记线程和COM对象,这里需要注意的是如果COM对象标记为STA,那么该COM对象只能被STA的线程访问,我们可以在注册表中通过ThreadingModel来设定
|
属性值 |
含义 |
|
Main (缺省值) |
主STA,也就是第一个创建的STA |
|
Apartment |
STA |
|
Both |
STA或者MTA都可以 |
|
Free |
MTA |
|
Neutral |
NTA |

StaSynchronizationContext(自定义的SynchronizationContext)
StaSynchronizationContext是STA线程的上下文环境,我们可以向该上下文环境发送消息,该上下文环境中的STA线程负责监听,如果发现有消息进入,则执行消息。
对于这个需求,核心就是如何实现监听?!

1、队列BlockingQueue
因为需要向该上下文环境发送消息,所以首先我们必须先建立一个结构来接收消息,同时该结构必须要线程安全、保持先进先出的顺序,并且还需要建立一个机制,如果在该结构中没有任何消息,那么这时调用Dequeue,该线程要一直等待,直到有消息进入或者手工释放该线程。
Code
2、SendOrPostCallbackItem
完成了消息结构,接下来就来实现消息对象了,它包含执行动作的委托实例、执行动作的方式(Send和Post)、事件信号。
向上下文环境发送消息可以有异步(Post)和同步(Send)两种方式,消息对象中的执行动作的方式就对应这两种方式,事件信号也是为了实现这个机制所必须的属性,具体的看后面的类
Code
该类负责的就是监听队列中是否有消息进入,如果有消息进入,则执行消息动作,否则一直等待,同时负责对STA线程的管理(启动,终止....)
特别说明的地方:
1、设置STA线程是通过"mStaThread.SetApartmentState(ApartmentState.STA)"实现的。
2、让该线程一直执行监听的方法是"While(true)",只有当调用Stop的时候,该监听才停止。
Code
该类继承于System.Threading.SynchronizationContext,类中包含了StaThread对象和队列。
需要特别说明的地方:
1、上下文环境中的STA线程是随着该上下文环境对象的创建而启动的
2、Send方法会等待SendOrPostCallback委托执行完成后,才运行下面的代码,也就是说这是同步的执行
通过"item.ExecutionCompleteWaitHandle.WaitOne()"这句话来实现的
3、Post方法和Send方法相反,是异步执行的
Code
OK,到这里StaSynchronizationContext就完成了,接下来我们做个DEMO来运行下吧!
Code
运行结果:
STA id 11 original thread 7 call count 0
STA id 11 original thread 12 call count 0
STA id 11 original thread 7 call count 1
STA id 11 original thread 12 call count 1
STA id 11 original thread 7 call count 2
STA id 11 original thread 12 call count 2
STA id 11 original thread 7 call count 3
STA id 11 original thread 12 call count 3
STA id 11 original thread 7 call count 4
STA id 11 original thread 12 call count 4
STA id 11 original thread 7 call count 5
STA id 11 original thread 12 call count 5
STA id 11 original thread 7 call count 0
STA id 11 original thread 12 call count 0
STA id 11 original thread 7 call count 1
STA id 11 original thread 12 call count 1
STA id 11 original thread 7 call count 2
STA id 11 original thread 12 call count 2
STA id 11 original thread 7 call count 3
STA id 11 original thread 12 call count 3
STA id 11 original thread 7 call count 4
STA id 11 original thread 12 call count 4
STA id 11 original thread 7 call count 5
STA id 11 original thread 12 call count 5
最后说明一下:
该StaSynchronizationContext中的线程并不一定要设置为STA,MTA也可以,在这里把线程设定为STA的目的:可以在该线程上,除了处理NET中的托管对象外,还可以处理一些非托管的对象(COM)。
写完了!
StaSynchronizationContext原代码:SynchronizationContext.rar
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。