2013-05-01 95 views
0

看来,如果给定的线程出于任何原因失败,这将导致无限循环。并行运行线程似乎导致无限循环

这是不是我写的代码,所以我甚至不能编辑它,但我觉得这里最明显的问题是,计数器变量totalActions没有标记为挥发性,和结果线程没有看到最新的值。

因此,它看起来像是从未得到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(); } 
    }); 
+1

此代码无关与TPL(比使用TPL就可以防止这种不正确的代码被写在首位的事实等。 ) – dlev 2013-05-01 19:53:40

+0

那么根据MSDN文档,挥发性的使用应保持在最低限度,如果使用的话。主要用于内存非常有限的嵌入式系统。他们建议使用'lock'关键字或另一个锁定机制,如互斥锁和信号灯。另外,使用'Interlocked.Decrement()'可以首先防止这个问题。因为这是一个原子动作,意味着一次只能有一个线程工作。 – Nomad101 2013-05-01 19:53:41

+0

@ Nomad101我知道在java中,你必须标记变量,以保证其他线程看到的值,否则将使用本地线程副本,这可能不是正确的值。在C#中,不正确的是 – loyalflow 2013-05-01 19:57:47

回答

0

锁将作为一个内存屏障,以确保您的测试if(totalActions > 0)读取当前值。我不相信这个代码是免费的,但是比赛至少是非常不可能的。你很难再现它。

所以这个问题是别的东西没有显示在这里。你可以使用调试器来找出涉及到的线程究竟在做什么吗?

你说一些线程死于未处理的异常。 也许早期退出的线程会导致计数不减。

此外,如果您不能更改代码,问题的重点是什么?我不知道该给你什么建议。

+0

usr,thanaks,我给出了一个示例用法,正是这些myService调用使api调用,并且如果终端处于关闭状态,当处于调试模式时,它会一直重复进行相同的调用,即DoSomething() – loyalflow 2013-05-01 20:01:25

+0

我更新了码。在调试时,我注意到一旦我的断点碰到了Monitor.Wait行,它实际上甚至都不会到达if语句的递减位置。这是无限循环的原因吗?不知道为什么它会继续尝试使它在失败时进行httprequest ... – loyalflow 2013-05-01 20:22:21

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(); 
    ... 
+0

对不起,实际的代码有,我不知何故错过了那一行抱歉! – loyalflow 2013-05-01 20:54:12

+0

好,那你最好做的就是把if条件改为if(Interlocked.CompareExchange(ref totalActions,0,0)> 0)' – YK1 2013-05-01 21:12:00