【问题标题】:Issue with thread barrier - PulseAll not reaching all threads线程障碍问题 - PulseAll 未到达所有线程
【发布时间】:2014-06-25 20:21:30
【问题描述】:

我有一个并行算法,但我遇到了一些障碍问题。在你们都尖叫“搜索”之前,我可以说我已经查看了可用的帖子和链接,并且我已经按照 Monitor.Wait 和 Monitor.PulseAll 的屏障说明进行操作,但我的问题是除了最后一个线程之外的所有线程都创建了(并启动) PulseAll 从我的主线程到达。以下是代码的基本布局:

public static object signal = new object(); //This one is located as class variable, not in the method

public void RunAlgorithm(List<City> cities){
    List<Thread> localThreads = new List<Thread>();
    object[] temp = //some parameters here
    for(int i = 0; i < numOfCitiesToCheck; i++){
        Thread newThread = new Thread((o) => DoWork(o as object[]));
        newThread.IsBackground = true; 
        newThread.Priority = ThreadPriority.AboveNormal;
        newThread.Start(temp as object);
        localThreads.Add(newThread);
    }

    //All threads initiated, now we pulse all
    lock(signal){
        Monitor.PulseAll(signal); 
    }
    int counter = 0;
    while(true){
        if(counter == localThreads.Count){ break; }
        localThreads[counter].Join();
        counter++;
    }
}

这就是主线程所做的(删除了一些不必要的部分),并且如前所述,主线程将始终卡在列表中最后一个线程的 Join() 中。 这是线程方法的样子:

private void DoWork(object[] arguments){
    lock(signal){
        Monitor.Wait(signal);
    }
    GoDoWork(arguments); 
}

我可以为这种类型的信号使用其他障碍吗?我想要的只是让主线程同时向所有线程发出信号,以便它们同时启动。我希望它们同时启动,以便尽可能接近并行(我测量算法的运行时间和其他一些事情)。我的障碍或代码的任何部分是否有缺陷(我的意思是障碍)?我尝试运行一个线程较少的实例,但它仍然卡在最后一个实例上,我不知道为什么会这样。我已经通过 VS debug 确认最后一个线程正在休眠(所有其他线程都是 !isAlive,而最后一个是 isAlive = true)。 任何帮助表示赞赏!

【问题讨论】:

  • 我收到错误消息说 Monitor.Wait 和 Monitor.PulseAll 没有在同步代码中执行 - 可能是我解释错了吗? @the race condition - 这是我的问题,但是我不知道如何让我的主线程等待足够长的时间。以前我在 PulseAll 之前有一个 Thread.Sleep(5),但这并没有解决问题。
  • 为什么要在这个低级别工作?为什么不直接使用 Barrier 类,让参与者的数量是您创建的线程数的 1+?
  • 从来没有听说过屏障类,我很惊讶我以前从未见过它。会看的,谢谢!

标签: c# multithreading parallel-processing barrier


【解决方案1】:

我设法使用 Barrier 类解决了这个问题。非常感谢 Damien_The_Unbeliever!仍然不敢相信我以前没有听说过。

public Barrier barrier = new barrier(1); 

public void RunAlgorithm(List<City> cities){
    List<Thread> localThreads = new List<Thread>();
    object[] temp = //some parameters here
    for(int i = 0; i < numOfCitiesToCheck; i++){
        barrier.AddParticipant(); 
        Thread newThread = new Thread((o) => DoWork(o as object[]));
        newThread.IsBackground = true; 
        newThread.Priority = ThreadPriority.AboveNormal;
        newThread.Start(temp as object);
        localThreads.Add(newThread);
    }

    barrier.SignalAndWait(); 
    int counter = 0;
    while(true){
        if(counter == localThreads.Count){ break; }
        localThreads[counter].Join();
        counter++;
    }
}


private void DoWork(object[] arguments){
    barrier.SignalAndWait();
    GoDoWork(arguments); 
}

【讨论】:

  • 你这样做的方式仍然有点冒险 - 例如如果您打算启动 4 个线程,并且刚刚完成第三次迭代,则当前参与者的数量为 3。如果 3 个“活动”线程在您下次调用 AddParticipant 之前都设法到达障碍,他们将获得越过障碍。这就是为什么我建议你将参与者的数量设为线程数的 1+(然后主线程在完成初始化后也会在屏障上执行 SignalAndWait
  • 啊,原来如此,谢谢,我会编辑我的代码!
猜你喜欢
  • 2011-04-16
  • 2012-01-05
  • 1970-01-01
  • 2021-10-30
  • 2011-07-29
  • 2018-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多