博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
backgroundWorker 的callback和主线程的调度
阅读量:5237 次
发布时间:2019-06-14

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

最近在工作中写了一段代码,同事在看code review的时候也提出了一些意见,讨论下来觉得挺有意思。

意图:

在一个UI界面,有一个相对耗时的操作耗时的操作要做,所以才用了传统的backgroundworker来完成这个事情;同时为了用户体验,将鼠标置忙。在backgroundworker里面完成之后再设置为普通状态。

方案:

在页面的构造函数中,设置并启动backgroundWorker:

updateUserWorker.DoWork +=   (sender, e) =>

            {

                ……;             

            }

updateUserWorker.RunWorkerCompleted   += new BunWorkerCompletedEventHandler(Worker_RunWorkerCompleted);

 

updateUserWorker.RunWorkerAsync();

 

在Form load event handler里面设置鼠标为忙状态:

if (updateUserWorker.IsBusy   == true)

{

    this.UseWaitCursor = true;

}     

在Worker_RunWorkerCompleted中将鼠标设置为普通:

try

{

……;

}

finally

{

    this.UseWaitCursor = false;

}

 

在code review中,同事提出,如果在form load event handler中,首先检查IsBusy为true,然后准备设置UseWaitCursor的时候,backgroundWorker完成了,请调用了RunWorkerCompleted,将UseWaitCursor设置为false,然后执行form load里面的this.UseWaitCursor = true;将会造成鼠标一直是忙状态。或者backgroundWorker会不会先调用completed,再设置IsBusy为false,这也会造成同样的问题。

初看来似乎颇有这个危险,但是后来仔细分析,应该确实没有这个问题。

  1. BackgroundWorker的completed event handler是在UI线程的callback。这个将会和Form Load Event handler在一个线程上执行。 如果线程正在执行Formload的IsBusy检查,应该是不会被callback抢断去执行completed event handler的。
  2. 透过反编译,我们可以看见backgroundWorker的内部实现为:

        private void AsyncOperationCompleted(object arg)

          {
              this.isRunning   = false;
              this.cancellationPending   = false;
              this.OnRunWorkerCompleted((RunWorkerCompletedEventArgs)arg);
          }

isRunning就是IsBusy的内部值,所以,是先设置了IsBusy然后再调用WorkerCompleted的。

Code review的疑问解决了,但是却给我带来了另外一个疑问:

一般来说,我们会用锁来保证一个代码段一次只有一个线程执行;那我们有办法保证一个线程在执行一个代码段的时候不会被打断么?这个也是有一点类似于对代码段的“原子操作”(只是类似,原来意义上的原子操作主要是针对一个变量的)。

比如说,在我们的这个例子中,如何保证在执行IsBusy检查之后,UI线程不会被抢断。或者,换一个说法可能更准确,在什么情况下,一个method执行到一半的时候会被暂停去执行另外一个method?

我想总体而言,应该是可以归纳为当线程处于空闲状态时,线程可能被唤起以执行completed callback。在sleep,suspend等状态均不可以。

  1. 比如,在使用MessageBox.Show 等待用户输入的时候。
  2. 在运行状态,callback不会被加入,必须等到运行结束执行。

不过,这些是我的一些观察结论,没有从根本上证明。

那么下一个问题是,如何知道一个线程处于空闲状态呢?可以通过代码解决么?

目前我还没找到,找到了过来update一下吧。

转载于:https://www.cnblogs.com/futureView/archive/2012/06/25/2561422.html

你可能感兴趣的文章
javascript中数组常用的方法和属性
查看>>
Apex 中 DML 进阶知识小结
查看>>
Apex 的 API 简介
查看>>
Salesforce 自定义元数据类型
查看>>
从网络服务生成Apex类
查看>>
Apex API 请求
查看>>
Java基础教程:Java内存区域
查看>>
SpringSecurity:深入浅出(1)
查看>>
Java分布式:分布式事务
查看>>
Java基础教程:多线程杂谈——Volatile
查看>>
SpringBoot学习笔记:Swagger实现文档管理
查看>>
Java基础教程:多线程杂谈——双重检查锁与Volatile
查看>>
微服务实践:服务运维
查看>>
SpringCloud学习笔记:服务支撑组件
查看>>
LeetCode:字符串相加【415】
查看>>
SpringBoot学习笔记:Redis缓存
查看>>
LeetCode:四数之和【18】
查看>>
微服务实践:分布式锁
查看>>
LeetCode:复原IP地址【93】
查看>>
LeetCode:第K个排列【60】
查看>>