【C#】【Thread】SynchronizationContext线程间同步
发布日期:2021-10-23 09:05:13 浏览次数:4 分类:技术文章

本文共 2452 字,大约阅读时间需要 8 分钟。

  SynchronizationContext在通讯中充当传输者的角色,实现功能就是一个线程和另外一个线程的通讯。

  需要注意的是,不是每个线程都附加SynchronizationContext这个对象,只有UI线程是一直拥有的。故获取SynchronizationContext也只能在UI线程上进行SynchronizationContext context = SynchronizationContext.Current;

  那什么时候会用到呢?

  在多线程操作时往往需要切回某个线程中去工作,等完成后再切回来。

  如主UI线程中创建了一个子线程A。A中添加了委托事件。UI线程中向A线程的类注册了事件,当A线程触发事件时去修改UI上的属性如TEXT。

  这个时候往往要在UI线程向子线程注册的事件方法中使用控件的invoke方法才能访问UI线程中的控件,因为这些注册的事件(委托)方法代码虽然看似写在UI线程的Form类中,但实际上是注册在了子线程A的事件中,它们是会被子线程A触发事件时在子线程内部执行的。这样,我们不得不在主UI线程的类的注册事件方法中通过控件的Invoke方法才能访问控件,这样做十分麻烦。我们想和系统的控件事件一样,直接在注册的事件方法中访问控件。那么这个时候就可以用SynchronizationContext了。

  SynchronizationContext.Send(SendOrPostCallback d,object state);

  SynchronizationContext.Post(SendOrPostCallback d,object state);

  d 为一个没有返回值,并且具有一个Object类型传入参数的委托(SendOrPostCallback );

  state 为执行这个委托时的参数(object);

注意:

  SynchronizationContext的对象不是所有线程都被附加的,只有UI主线程会被附加。

  对于UI线程来说,是如何将SynchronizationContext这个对象附加到线程上的呢?

  在Form1 form = new Form1()之前,SynchronizationContext对象是为空,而当实例化Form1窗体后,SynchronizationContext对象就被附加到这个线程上了。

  所以可以得出答案了:当Control对象被创建的同时,SynchronizationContext对象也会被创建并附加到线程上。所以在使用时,一定要等窗体InitializeComponent(); 这个完成后 它才能得到一个不是NULL的对象.

  

  那么SynchronizationContext的Send()和Post()二个方法有什么区别呢?

  Send() 是简单的在当前线程上去调用委托来实现(同步调用)。也就是在子线程上直接调用UI线程执行,等UI线程执行完成后子线程才继续执行。

  Post() 是在线程池上去调用委托来实现(异步调用)。这是子线程会从线程池中找一个线程去调UI线程,子线程不等待UI线程的完成而直接执行自己下面的代码。

  

例子:

///         /// 这里需要在主线程里定义,        /// 并在主线程获得context = SynchronizationContext.Current        ///         private SynchronizationContext context;        ///         /// 窗体加载        ///         ///         ///         private void Form1_Load(object sender, EventArgs e)        {            //此处就是之前提的在主线程获得SynchronizationContext            context = SynchronizationContext.Current;            //之后可以开线程了            Thread thread = new Thread(new ThreadStart(Start));            thread.IsBackground = true;            thread.Start();        }        ///         /// 线程操作        ///         private void Start()        {             for(int i=0;i<100;++i)            {                //这边即可正常调用主界面的控件了                context.Send(operation, i);//正确                //按原先直接应用,因为使用到控件会报错                operation(i);//报错                Thread.Sleep(100);            }        }        ///         /// 线程操作        ///         ///         private void operation(object obj)        {            textBox1.AppendText(obj.ToString() + "\r\n");         }

 

参考文章:

 

转载于:https://www.cnblogs.com/mqxs/p/4288644.html

转载地址:https://blog.csdn.net/weixin_30549657/article/details/95794432 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:nodejs开发环境的搭建
下一篇:Node Security

发表评论

最新留言

很好
[***.229.124.182]2024年04月13日 19时27分49秒