privateObject MarshaledInvoke( Control caller, Delegate method, Object[] args, boolsynchronous ) {if(!IsHandleCreated) {thrownewInvalidOperationException(SR.GetString(SR.ErrorNoMarshalingThread));}ActiveXImpl activeXImpl = (ActiveXImpl)Properties.GetObject(PropActiveXImpl); if(activeXImpl != null) {IntSecurity.UnmanagedCode.Demand; } // We don't want to wait if we're on the same thread, or else we'll deadlock. // It is important that syncSameThread always be false for asynchronous calls. // boolsyncSameThread = false;intpid; // ignored if(SafeNativeMethods.GetWindowThreadProcessId( newHandleRef( this, Handle), outpid) == SafeNativeMethods.GetCurrentThreadId) {if(synchronous)syncSameThread = true;} // Store the compressed stack information from the thread that is calling the Invoke// so we can assign the same security context to the thread that will actually execute// the delegate being passed.// ExecutionContext executionContext = null;if(!syncSameThread) {executionContext = ExecutionContext.Capture; } ThreadMethodEntry tme = newThreadMethodEntry(caller, this, method, args, synchronous, executionContext);lock( this) {if(threadCallbackList == null) {threadCallbackList = newQueue;} } lock(threadCallbackList) {if(threadCallbackMessage == 0) {threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion + "_ThreadCallbackMessage");} threadCallbackList.Enqueue(tme); } if(syncSameThread) {InvokeMarshaledCallbacks; } else{// UnsafeNativeMethods.PostMessage( newHandleRef( this, Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);} if(synchronous) {if(!tme.IsCompleted) {WaitForWaitHandle(tme.AsyncWaitHandle); } if(tme.exception != null) {throwtme.exception;} returntme.retVal;} else{return(IAsyncResult)tme;} } Invoke的机制就保证了一个共享变量只能由一个线程维护 , 这和GO语言使用通信来替代共享内存的设计是暗合的 , 他们的理念都是 "让同一块内存在同一时间内只被一个线程操作"。 这和现代计算体系结构的多核CPU(SMP)有着密不可分的联系 ,
这里我们先来科普一下CPU之间的通信MESI协议的内容 。 我们知道现代的CPU都配备了高速缓存 , 按照多核高速缓存同步的MESI协议约定 , 每个缓存行都有四个状态 , 分别是E(exclusive)、M(modified)、S(shared)、I(invalid) , 其中:
M:代表该缓存行中的内容被修改 , 并且该缓存行只被缓存在该CPU中 。 这个状态代表缓存行的数据和内存中的数据不同 。
E:代表该缓存行对应内存中的内容只被该CPU缓存 , 其他CPU没有缓存该缓存对应内存行中的内容 。 这个状态的缓存行中的数据与内存的数据一致 。
I:代表该缓存行中的内容无效 。
S:该状态意味着数据不止存在本地CPU缓存中 , 还存在其它CPU的缓存中 。 这个状态的数据和内存中的数据也是一致的 。 不过只要有CPU修改该缓存行都会使该行状态变成 I。
四种状态的状态转移图如下:
文章图片
我们上文也提到了 , 不同的线程是有大概率是运行在不同CPU核上的 , 在不同CPU操作同一块内存时 , 站在CPU0的角度上看 , 就是CPU1会不断发起remote write的操作 , 这会使该高速缓存的状态总是会在S和I之间进行状态迁移 , 而一旦状态变为I将耗费比较多的时间进行状态同步 。
这里我们先来科普一下CPU之间的通信MESI协议的内容 。 我们知道现代的CPU都配备了高速缓存 , 按照多核高速缓存同步的MESI协议约定 , 每个缓存行都有四个状态 , 分别是E(exclusive)、M(modified)、S(shared)、I(invalid) , 其中:
M:代表该缓存行中的内容被修改 , 并且该缓存行只被缓存在该CPU中 。 这个状态代表缓存行的数据和内存中的数据不同 。
E:代表该缓存行对应内存中的内容只被该CPU缓存 , 其他CPU没有缓存该缓存对应内存行中的内容 。 这个状态的缓存行中的数据与内存的数据一致 。
I:代表该缓存行中的内容无效 。
S:该状态意味着数据不止存在本地CPU缓存中 , 还存在其它CPU的缓存中 。 这个状态的数据和内存中的数据也是一致的 。 不过只要有CPU修改该缓存行都会使该行状态变成 I。
四种状态的状态转移图如下:
文章图片
我们上文也提到了 , 不同的线程是有大概率是运行在不同CPU核上的 , 在不同CPU操作同一块内存时 , 站在CPU0的角度上看 , 就是CPU1会不断发起remote write的操作 , 这会使该高速缓存的状态总是会在S和I之间进行状态迁移 , 而一旦状态变为I将耗费比较多的时间进行状态同步 。
特别声明:本站内容均来自网友提供或互联网,仅供参考,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
