zoukankan      html  css  js  c++  java
  • 【C#】【Thread】SynchronizationContext线程间同步

      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线程的完成而直接执行自己下面的代码。

      

    例子:

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

    参考文章:http://blog.csdn.net/iloli/article/details/16859605

  • 相关阅读:
    HTTP content-type
    python3学习--安装OCR识别库tesserocr
    http post get 类库 httphelper
    MD5
    解决python3中cv2读取中文路径的问题
    web api获得Post数据为空的解决办法
    python3项目打包成exe可执行程序
    pip install 使用国内镜像
    win10家庭版组策略安装
    在国企的日子(第七章 转正)
  • 原文地址:https://www.cnblogs.com/mqxs/p/4288644.html
Copyright © 2011-2022 走看看