【问题标题】:Telling "other" Tasks to pause in C#在 C# 中告诉“其他”任务暂停
【发布时间】:2015-02-17 02:21:08
【问题描述】:

我有以下:

[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 的错误。通常,如果proxyDrivers 之一遇到这种情况,它们都会立即发生。我需要防止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){}
          }  
 }

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

【问题讨论】:

  • 您的代码不完整或有错字:有时您使用_isPaused,有时使用isPaused
  • HandleIntro(proxyDriver, target) 方法不包括在内 - 同样只需要一个参数。
  • @SebastianNegraszus - 这是一个错字。我试图简化代码,所以请原谅任何小的不一致
  • @Kami 这是一个错字。我试图简化代码,所以请原谅任何小的不一致
  • 顺便说一句 - 您知道在循环中调用 var rnd = new Random(); 会导致使用相同的种子,因此您的调用 var r = rnd.Next(itemArray.Count); 可以产生相同的值吗?您确实需要在类级别实例化一次rnd

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


【解决方案1】:

您正在跨各种任务共享_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 在任务关闭之前重新启动。

【讨论】:

  • 谢谢。当其他任务尝试访问 FixProblem 时会发生什么?在 FixProblem 完成之前,我需要它们保持活力。
  • @RobVious 第一个到达 lock 语句的线程将阻塞所有其他线程,直到它完成 - msdn.microsoft.com/en-us/library/ms173179.aspx。我在示例代码中添加了对 motherDriverNeedsToBeRestarted 的检查 - 这将是一种方法或类似的方法,用于检查是否需要重新启动 motherDriver 以防止重复重新启动。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-04-23
    • 2015-03-26
    • 1970-01-01
    • 2014-08-16
    • 2018-07-04
    • 2016-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多