似乎如果给定的线程因任何原因失败,这将导致无限循环。
这是我不能编写的代码,所以我甚至无法编辑它,但我认为这里最明显的问题是计数器变量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(); }
});
答案 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();
...