详解 SynchronizationContext

        本人查阅了许许多多的中文资料,始终没有找到一个合适的介绍。直到我找到了一篇讲得透透的英文介绍才明白SynchronizationContext到底是个啥玩意。Understanding SynchronizationContext (Part I)

接下来就是我个人结合自己的项目经历与该篇文章进行讲解。

SynchronizationContext 作用的简单介绍

        简单的来说SynchronizationContext就是用来在不同线程中进行通讯的一个类。SynchronizationContext的作用就是能够让一个线程去沟通另外一个线程,即线程之间的互相通信。
        我们来假设一下,如果你有两个线程,分别是Thread1Thread2,然后有些业务逻辑是我在Thread2中执行时,想要去执行Thread1中的一些代码,这个时候就要用到SynchronizationContext这个类来帮助我们完成了。这样说起来可能有点抽象,举个实际例子,我们在UI线程以外,执行了一些后台的线程,比如动态更新时间(虽然有ticker方法),我们希望这个后台执行的时间线程能够将时间的显示更新在UI界面的时间显示label上,但我们不能直接在时间线程里调用UI中的label.Text属性进行直接修改(不信的话可以尝试,会报错),在这个情况下就要在时间线程里用到SynchronizationContext类来通知UI线程从而进行时间更新。(具体实例见后面)
        到这里可能有细心的小伙伴发现,那这个SynchronizationContext也没有啥特别之处鸭,我们可以通过UI控件的Invoke方法进行更新UI界面的操作鸭。真的是这样吗?实则不然,有一些线程的业务逻辑不是这样的,比如对一些变量的控制,我们不需要将这些变量显示在UI界面上,但是我们需要一个方法,能够在线程对这个变量进行操作后,通知UI线程进行下一步的业务逻辑。如果我们将这个通知绑定到一个无关的控件上,这会平白无辜的增加控件的附加功能,是不利于大型开发与设计的,这个时候SynchronizationContext的作用就必不可少了。

SynchronizationContext 具体实例

先来看一段简单的C# form代码:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void mToolStripButtonThreads_Click(object sender, EventArgs e)
    {
    	//获取当前线程的ID(UI线程)
        int id = Thread.CurrentThread.ManagedThreadId;
        Trace.WriteLine("mToolStripButtonThreads_Click thread: " + id);

   		//记录当前线程的上下文,是之后线程通信主线程的基础
        SynchronizationContext uiContext = SynchronizationContext.Current;
        //创建线程
        Thread thread = new Thread(Run);
        //uiContext这个上下文类作为参数传递给线程thread并启动该线程
        thread.Start(uiContext);
    }

    private void Run(object state)
    {
        //显示当前执行线程的ID
        int id = Thread.CurrentThread.ManagedThreadId;
        Trace.WriteLine("Run thread: " + id);

        //将传递进来的上下文参数转化为SynchronizationContext 类
        SynchronizationContext uiContext = state as SynchronizationContext;

        for (int i = 0; i < 1000; i++)
        {
            Thread.Sleep(10);
            uiContext.Post(UpdateUI, "line " + i.ToString());
        }
    }
	//线程的具体方法实现
    private void UpdateUI(object state)
    {
        int id = Thread.CurrentThread.ManagedThreadId;
        Trace.WriteLine("UpdateUI thread:" + id);
        string text = state as string;
        mListBox.Items.Add(text);
    }
}

然后我们看看实现的结果:


mToolStripButtonThreads_Click thread: 10
Run thread: 3
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
UpdateUI thread:10
... (x1000 次)

SynchronizationContext的两种常用方法post和send

        既然已经介绍完SynchronizationContext的具体实例,接下来就向大家介绍一下SynchronizationContext的两种实用的方法。
        分别是.Post(function, state).Send(function, state)。其中function为需要执行的函数,state可以理解为该函数的一个object类型的参数。(大家不要觉得这个object参数感觉不太好使,其实懂得c#类型转换的人都知道,通过as就能将object类型转换成任何类型,可以说是非常的实用)
        对于.Post(function, state)方法就是异步的方法,那什么是异步,就是你当前线程执行.Post(function, state)时,该线程不会等待.Post(function, state)中的函数执行结束才执行后面的代码,而是直接接着执行后面的代码。这样可以提高程序的运行效率,不过牵扯到数据的话,还是要注意一下,因为你不知道.Post(function, state)中的函数是否执行完毕,也就意味着你所期待的数据不知道是否已经发生了改变。
        而.Send(function, state)方法就是同步的方法,意味着当线程执行到.Send(function, state)这条语句是时候,只有当.Send(function, state)中的函数顺利执行完毕后才会执行后面的代码。这样的好处就是容易控制数据。

SynchronizationContext的局限性

        看上去好像SynchronizationContext非常的实用,方便用户在不同线程之间进行通讯,但是事实上没有那么简单。其实SynchronizationContext这个类只能做到UI线程和其他线程之间的通信,如果想实现任意线程之间的通信还是需要自己去定义一个新的类,如果大家感兴趣的话,私聊我,我愿意把该方法的实现公开出来。

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值