【问题标题】:lock with while loop on multthread application form c# blocking all threads on single core machine在多线程应用程序表单上使用while循环锁定c#阻塞单核机器上的所有线程
【发布时间】:2013-08-31 15:33:54
【问题描述】:

我在 Windows 窗体 C# 应用程序上的多线程应用程序有问题。该应用程序在多核机器上运行良好,但是当它在单核机器上运行时,所有线程都挂起。我用的是backgroundWorker,代码如下:

 class custonTime // delay class
 {
     public void sleep_sec(int sleep)
     {
         int time_now = Environment.TickCount;
         int time_sleep = sleep;
         while ((Environment.TickCount - time_now) < time_sleep) ;
     }
 }

当我按下 UI 上的按钮时,标志 actiondoAlways 设置为 true 并启动以下后台工作程序。 backgorundworker1 在其他人执行任务的正确时间等待并触发任务:

 private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
 {
     while(action)
     {
         if(doItAlways)
         {
             //do important tasks
         }
         if(task1)
         { 
             //do things
             task1 = false;
         }
         if(task2)
         { 
             //do things
             task1 = false;
         }
    }
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    task1=true;
    manegerTimewr2.sleep_sec(12000);//call delay class to wait 12 secs
    task2=true;
    manegerTimewr2.sleep_sec(12000);//call delay class to wait 12 secs
}

我的延迟类不仅锁定了我的backgorundworker1,还锁定了backgroundworker2,这使得无法执行标志doItAlways 触发的任务,只有在while 循环完成时才会释放应用程序。

而且它只发生在单核机器上。

还有其他方法吗?一种直接而简单的方法来挂起一个线程直到经过一段时间而不阻塞其他线程?

注意Thread.Sleep 不起作用,因为不同机器上经过的时间差异太大。

【问题讨论】:

  • 像这样一个非常紧凑的循环... while ((Environment.TickCount - time_now)
  • 这正是发生的事情,我能做些什么来防止它?
  • 这段代码的坏处不止一个。永远不要使用 bool 在线程之间发出信号,不能保证另一个线程可以看到值的变化。请改用 AutoResetEvent。并且永远不要编写热等待循环,至少使用 Thread.Sleep()。在这里使用两个线程根本没有意义,第一个可以简单地自行延迟。从您当地的图书馆或书店拿起一本关于线程的书,您根本没有做对。
  • 对不起我的代码是垃圾 =D,但是已经在代码上实现了 AutoResetEvent,有点棘手但结果相同,线程睡眠不能使用,因为需要控制时间,两个线程都是必要的,因为我需要访问一个自动化系统,这不能通过不同的线程来完成
  • 请解释“不同机器上经过的时间差异太大”。你自己的代码应该使用TimeSpan.TicksPerSecond,如果它打算在所有可能的.NET实现上工作相同的话。您还应该将 .NET 和 TPL 中的各种 Timer 类视为管理任务的更好方法。

标签: c# multithreading winforms


【解决方案1】:

问题是,BackgroundWorker 在内部使用线程池,该线程池通常包含与机器上的 CPU/内核相同数量的线程。因此,在单 CPU 机器上,您将只有一个线程处理 BackgroundWorker,我猜它们是按顺序安排的,因此第一个线程同时运行 sleep_sec 调用,并且只有 之后,第二个线程才开始.

另一方面,在多核机器上,线程池中有更多线程,因此它可以按预期工作。

您可以使用“普通”Thread(连同Thread.Sleep,不要使用while 循环)作为“等待”,因为这不需要任何 UI 交互。您也可以只使用 Timer 对象,这正是为此目的(在指定时间后触发事件)。

【讨论】:

    【解决方案2】:

    使用此方法实现等待指定时间量:Thread.Sleep

    【讨论】:

      【解决方案3】:

      不要使用BackgroundWorker,而是启动一个新的Thread,并手动为该线程设置ThreadPriority。然后您就可以使用Thread.Sleep 并且它应该更精确地工作,因为线程具有更高的优先级。以下是您应该得到的结果:

      void Run()
      {
          // some initialization stuff
          new Thread(DoWork1) { Priority = ThreadPriority.AboveNormal }.Start();
          new Thread(DoWork2) { Priority = ThreadPriority.Highest }.Start();
      }
      
      private void DoWork2()
      {
          while (action)
          {
              if (doItAlways)
              {
                  //do important tasks
              }
              if (task1)
              {
                  //do things
                  task1 = false;
              }
              if (task2)
              {
                  //do things
                  task1 = false;
              }
              Thread.Sleep(1);
          }
      }
      
      private void DoWork1()
      {
          task1 = true;
          Thread.Sleep(12000);//call delay class to wait 12 secs
          task2 = true;
          Thread.Sleep(12000);//call delay class to wait 12 secs
      }
      

      【讨论】:

        猜你喜欢
        • 2010-09-05
        • 1970-01-01
        • 2018-11-29
        • 2021-10-30
        • 2019-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多