并行运行线程似乎导致无限循环

时间:2013-05-01 19:50:07

标签: c# multithreading task-parallel-library

似乎如果给定的线程因任何原因失败,这将导致无限循环。

这是我不能编写的代码,所以我甚至无法编辑它,但我认为这里最明显的问题是计数器变量totalActions没有标记为volatile, ,因此线程没有看到最新的值。

所以如果它永远不会得到totalActions的实际价值,它会继续等待吗?

这会导致线程以递归方式运行吗?在调试时,我注意到正在执行的线程失败(异常被抛出),并且它一直被一遍又一遍地调用....

public void PerformActions(List<Action> actions)
{
   object actionLock = new object();
   int totalActions = actionts.Count;

   for(int x = 0; x < accounts.Count; x++)
   {
      int y = x;
      new Thread(delegate()
      {
        actions[y].Invoke();

        if(Interlocked.Decrement(ref totalActions) == 0)
        {
            lock(actionLock)
            {
                Monitor.Pulse(actionLock);
            }
        }
    }).Start();
   }

   lock(actionLock)
   {
        if(totalActions > 0)
        {
           Monitor.Wait(actionLock);
        }    
   }
}

更新

用法就是这样,myService正在进行httpRequest调用以从API服务中获取json请求。

Execute.InParallel(
new Action[]
    {
    () => { abc = myService.DoSomething(); },
    () => { def = myService.DoSomethingElse(); }
    });

2 个答案:

答案 0 :(得分:0)

锁将充当内存屏障,确保您的测试if(totalActions > 0)读取当前值。我不相信这个代码是无竞争的,但竞争至少是非常非常不可能的。你很难再现它。

所以问题是这里没有显示的其他问题。你能用调试器找出所涉及的线程到底在做什么吗?

你说有些线程因未处理的异常而死亡。 可能早期退出的线程导致计数不会减少。

另外,如果您无法更改代码,那么问题的重点是什么?我不确定该向你推荐什么。

答案 1 :(得分:0)

循环不正确 - 因为变量x被错误捕获。当在每个线程中执行actions[x].Invoke();时,它将始终具有x的最后一个值。因此,传递给数组的最后一个委托将被多次调用。

正确的方法是这样的

    for(int x = 0; x < accounts.Count; x++)
       {
          int y = x; // here correct value of y will be captured in delegate
          new Thread(delegate()
          {
            actions[y].Invoke();
   ...