c# 数据出现错误! 线程间操作无效: 从不是创建控件_【C#】窗体程序如何保证线程安全...

声明:本文章的部分内容来源于 《more effective c#》

很多程序员都认为多线程编程是一件充满b格的事情,但是,对多线程的不正当使用,很可能引起严重复杂,难以调试的错误。本文的目的,在于向你提供几种让你的线程编程变得更加安全有效的方案。

根据官方文档,我们先展示一种非线程安全的线程使用方式。

private 

这段代码的功能非常简单,用 button1 去控制 text1,但是当你运行这段代码的时候,visual studio 自带的检测机制不会让你 debug 成功。并报出:Cross-thread operation not valid. Control "" accessed from a thread other than the thread it was created on.

官方文档的这个例子举得很好,这个例子的本质是:button1 的单击函数中的线程想控制 text1,但是 button1 启用的这个线程并不是创建 text1 的那一个,这就违反了线程调用的基本原则:不能跨线程调用。

那么,我们应该如何使用一种线程安全的编码方式呢?

答案一,使用 invoke,以及 invokeRequired 参数。

这种方法的本质是利用委托让主线程去改变控件的属性,也就是让创建了控件的线程去管理控件,这是符合线程安全原则的。如果还不理解,我试着用生活中的例子举例,有两个关系特别好的人,A 和 B,A有一笔钱,他还有记账的习惯,他的原则是帐不能乱。A 说愿意把钱借给 B,于是 B 可以直接从 A的钱包里面取钱,B今天需要钱,看到A钱包里面有100(内存),拿走了 50 放到自己口袋(CPU寄存器),把剩下的50放回A的钱包里,A也需要钱,从自己钱包里拿走50,把剩下的50放回钱包,此时就有了一个问题,由于两者恰好同时拿钱,他们都认为钱包里面原本有100块(这一点与现实生活中取钱不太一样,因为现实中的取钱是绝对做不到微观并发的,即相同的五十块无法被两人同时拿到,所以你可以理解为他们复制了当前钱包的状态),拿走50后,钱包里还有50,而真实的结果应当是一元不剩,但是A记账为50。这就是线程不安全导致的数据不一致问题。

ef1091fb2cfafc640c61d17a679781d6.png

换句话说,就算你们两个人的关系再好,别人借钱的时候也应该经过你的同意,向你发一个申请,你把钱从钱包里拿出来,再给他。而这意味着什么呢,意味着,A 和 B 的并行操作在取钱的这一个微小的局部上重新变成了串行。A 自己拿钱的操作和 A 替 B 拿钱的操作都是A自己执行的,因此不会产生乱账(数据不一致)的现象。

这里我还想重点讲一下 InvokeRequired 这个属性,为了尽可能避免歧义,我直接翻译一下官方文档吧,这个属性会比较创建控件的线程 id试图调用该控件的线程 id,如果线程 id不一致,那么该属性即为 true,函数就会委托主线程让主线程去调用这个方法。

那么我们修改后的程序为:

using 

其中 WriteTextSafe 这一个函数被两次调用,第一次调用时 thread2 调用的,然后它委托主线程去重新调用该函数,于是第二次时,主线程再一次调用该函数,并更新 textBox1 控件。

答案二:使用 background worker

由于 background worker 我已经在我的另一篇文章里面做了比较详细的介绍,我这里不进行展开。

Mike:【c#】关于 BackGroundWorker 的用法讲解(附实例)​zhuanlan.zhihu.com

但是,有几点关键的地方我还需要重申一下:

一般而言,我们要在主线程(Form 线程)里申请这个 background worker 实例,并为其三个关键的 property 挂载 handler,这三个 property 分别为 DoWork,ProgressChanged 和 RunWorkerCompleted。

其中,绑定在 DoWork 上面的 handler 是后台线程的。绑定在 ProgressChanged 和 RunWorkerCompleted 上面的 handler 是主线程的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值