【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的Sendt()和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() + "\r\n"); 

        }

 

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

 

你可能感兴趣的:(context)