【问题标题】:WaitOne() waits forever even though all events fired即使所有事件都已触发,WaitOne() 也会永远等待
【发布时间】:2012-12-26 22:47:21
【问题描述】:

Threaded 应该创建 4 个单独的线程并等待每个线程完成。每个线程都会休眠一段时间,并且仅在共享的 Mutex opbject 未被另一个线程占用时终止,然后通过事件发出信号表明它已完成(这是我的代码的简化版本,但在同一位置失败)

但是发生的情况是,大多数情况下,主线程会在 WaitOne() 之一看似随机地永远等待。

我还必须注释掉我的代码的某些部分,因为它会导致更多意想不到的行为(即,在每个线程完成后,主线程会以某种方式跳回 for 子句并导致 IndexOutOfBounds)

class Threading
{
    static Mutex CM;
    static List<Manga> SharedList;
    static ManualResetEvent CEvent = new ManualResetEvent(false);
    static ManualResetEvent Event1 = new ManualResetEvent(false);
    static ManualResetEvent Event2 = new ManualResetEvent(false);
    static ManualResetEvent Event3 = new ManualResetEvent(false);
    static ManualResetEvent Event4 = new ManualResetEvent(false);

   public List<Manga> ThreadedMangaIndexCrawl(int MaxThreads)
   {
       CM = new Mutex(false);
       SharedList = new List<Manga>();

       ManualResetEvent[] evs = new ManualResetEvent[4];
       evs[0] = Event1;    // Event for t1
       evs[1] = Event2;    // Event for t2
       evs[2] = Event3;    // Event for t3
       evs[3] = Event4;    // Event for t4

       /*for (int i = 0; i < MaxThreads + 1; i++)
       {
           if (i > MaxThreads)
           { break; }
           Thread t = new Thread(() => this.StartIndexCrawling(1,i,i+1,evs[i]));
           t.Start();
       }*/
       int i = 0;
       Thread t1 = new Thread(() => this.StartIndexCrawling(1, i, i + 1, evs[i]));
       t1.Name = "Thread" + i;
       t1.Start();
       i++;
       Thread t2 = new Thread(() => this.StartIndexCrawling(1, i, i + 1, evs[i]));
       t2.Name = "Thread" + i;
       t2.Start();
       i++;
       Thread t3 = new Thread(() => this.StartIndexCrawling(1, i, i + 1, evs[i]));
       t3.Name = "Thread" + i;
       t3.Start();
       i++;
       Thread t4 = new Thread(() => this.StartIndexCrawling(1, i, i + 1, evs[i]));
       t4.Name = "Thread" + i;
       t4.Start();


      /* foreach (var e in evs)
       { 
           e.WaitOne(); 

       }*/

       evs[0].WaitOne();
       evs[1].WaitOne();
       evs[2].WaitOne();
       evs[3].WaitOne(); 

       return SharedList;
   }

   void StartIndexCrawling(int Target, int Start, int End, ManualResetEvent E)
   {
       Thread.Sleep(1000);
       CM.WaitOne();
       CM.ReleaseMutex();
       E.Set();
   }
}

任何帮助都会很棒

【问题讨论】:

  • 您是否创建了多个这些对象?对于非单例对象,静态成员似乎相当危险。
  • 考虑使用Tasks 清理这个逻辑。
  • @roken:我认为 Tasks 不会清理那里的执行流程混乱,这只是使用更多 enat 助手/扩展进行异步工作的另一种构造
  • 您的意思是多个“线程”吗?不,我只是做一个实例
  • 看来你从来没有将 CM 互斥体切换到信号状态,所以这是一场比赛

标签: c# multithreading waitone


【解决方案1】:

很可能,所有四个线程都会执行:

this.StartIndexCrawling(1, 3, 3 + 1, evs[4]);

这与您使用闭包有关。所有四个线程都将绑定到变量i,并在代码执行后使用它所具有的任何值(而不是创建Thread 对象时的值)。

如果所有四个线程都使用相同的值,您的代码就不可能工作。

【讨论】:

  • 也可以看看这个帖子stackoverflow.com/questions/271440/…
  • 我会被诅咒的。这是我认为是原因的最后一件事。但是为什么线程使用当前的 i 而不是他们通过参数获得的 i 执行自己? //edit 发布后才看到链接
  • StartIndexCrawling 中,您拥有值的本地副本。但是线程的最顶层代码是闭包() =&gt; this.StartIndexCrawling(1, i, i + 1, evs[i]) 定义的匿名函数。这段代码引用了共享变量i。这就是闭包的工作原理。
【解决方案2】:

查看 Codo 的回答。
以下是您应该采取的措施来解决它:

   int i = 0;
   Thread t1 = new Thread(() => this.StartIndexCrawling(1, 0, 1, Event1));
   t1.Name = "Thread" + i;
   t1.Start();
   i++;
   Thread t2 = new Thread(() => this.StartIndexCrawling(1, 1, 2, Event2));
   t2.Name = "Thread" + i;
   t2.Start();
   i++;
   Thread t3 = new Thread(() => this.StartIndexCrawling(1, 2, 3, Event3));
   t3.Name = "Thread" + i;
   t3.Start();
   i++;
   Thread t4 = new Thread(() => this.StartIndexCrawling(1, 3, 4, Event4));
   t4.Name = "Thread" + i;
   t4.Start();

【讨论】:

    猜你喜欢
    • 2010-12-27
    • 1970-01-01
    • 2018-02-20
    • 2011-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多