最近在工作中写了一段代码,同事在看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一下吧。

posted on 2012-06-25 16:17  Justin Sun  阅读(583)  评论(0编辑  收藏  举报