告诉"其他"要在C#中暂停的任务

时间:2015-02-16 10:59:24

标签: c# asp.net asynchronous async-await

我有以下内容:

[TestMethod]
public async Task Start() 
{
   var numDrivers = 2;
   List<Task> tasks = new List<Task>();
   var motherDriver = GetMotherDriver();
   while (numDrivers != 0) 
   {
       var rnd = new Random();
       var r = rnd.Next(itemArray.Count);

       var target = itemArray[r];
       var proxyDriver = GetProxiedDriver();

       tasks.Add(Task.Run(() => HandleIntro(proxyDriver)));
       numDrivers--;
   }

   await Task.WhenAll(tasks);
}

这是有效的,但每隔一段时间,HandleIntro就会遇到需要重置motherDriver的错误。通常如果其中一个proxyDriver点击这种情况,所有这些都会立即发生。我需要阻止motherDriver多次重生,所以我尝试使用布尔isPausedwhile循环来管理它。从HandleIntro开始,我尝试使用第一个任务设置的全局变量来告诉其他人暂停直到完成:

 private bool _isPaused;

 private async Task Start(){ 
   _isPaused = false;
   //code
 }

 private async Task HandleIntro(Driver driver) {
       // wait for isPaused to get set to false
       while(_isPaused){}
       // do stuff
       if(errorOccurs){
           FixProblem();
       }
 }

 private void FixProblem(){
         if (!_isPaused){
             _isPaused = true;
             // spawn new motherDriver
             _isPaused = false;
         } else{
             // hold here until other thread sets isPaused = false
             while (_isPaused){}
          }  
 }

但是编译器告诉我while (_isPaused)中的FixProblem总是true - 好像它没有看到该值在某个时刻被另一个线程设置。这告诉我,我正在以错误的方式解决这个问题。这是正确的方法吗?如何妥善处理?

2 个答案:

答案 0 :(得分:2)

volatile关键字添加到_isPaused字段可能会解决问题,但我建议您与lock使用正确的同步。

答案 1 :(得分:2)

您正在各种任务中共享_isPaused变量。因此,当一个任务改变变量的值时;所有线程都进入新的motherDriver初始化过程。

您需要同步对重新启动motherDriver控制块的访问权限,以确保只有一个线程可以重新启动该进程。尝试类似:

private static object objectlock = new object();

private void FixProblem(){
   lock(objectlock)
   {
      if (!_isPaused && motherDriverNeedsTobeRestarted){
         _isPaused = true;
         // spawn new motherDriver
         _isPaused = false;
      }
   }
}

这将确保在出现问题时,motherDriver在任务关闭之前重新启动。