[英]Exit a loop if another thread enter in the
我有一个多线程问题。
我有一个方法可以对多个项目进行刷新。
在这种方法中,我遍历项目列表并刷新其属性之一。
该列表包含很多元素,我们必须做一些数学运算才能计算出它的属性。
该操作的当前代码如下所示:
public void AddItemsWithLayoutRefresh(IEnumerable<MyItem> items){
_control.Invoke(()=>{
AddItems(items);
for(int i =0;i<_guiItems.Count;i++){
//The goal is to have a condition here to "break" the loop and let the next call to RefreshLayout proceed
_guiItems[i].Propriety = ComputePropriety(_guiItems[i]);
}
});
}
问题是我可能有4个通话,当前仅在Invoke
上阻塞。 我必须完成“ AddItems”方法,但是对于“ for”循环中的所有内容,如果我知道它会在之后执行,那么我可以毫无问题地中止此操作。
但是如何以线程安全的方式做到这一点?
如果我放一个private bool _isNewRefreshHere;
,进入调用,然后在检查之前设置为true的Invoke
,我不保证,有没有两个呼叫有到达调用之前我检查它在for循环。
那么当对方法进行新的调用时,如何在进入循环时break
?
解决方案根据Andrej Mohar的回答,我做了以下工作:
private long m_refreshQueryCount;
public void AddItemsWithLayoutRefresh(IEnumerable<MyItem> items){
Interlocked.Increment(ref m_refreshQueryCount);
_control.Invoke(()=>{
Interlocked.Decrement(ref m_refreshQueryCount);
AddItems(items);
for(int i =0;i<_guiItems.Count;i++){
if (Interlocked.Read(ref m_refreshQueryCount) > 0)
{
break;
}
_guiItems[i].Propriety = ComputePropriety(_guiItems[i]);
}
});
}
这似乎工作得很好
我将通过以下方式进行操作:
private readonly object _refresherLock = new object();
private bool _isNewRefreshHere = false;
private AutoResetEvent _refresher = new AutoResetEvent(true);
public void AddItemsWithLayoutRefresh(IEnumerable<MyItem> items)
{
lock (_refresherLock)
{
if (_isNewRefreshHere)
{
return;
}
_isNewRefreshHere = true;
}
_refresher.WaitOne();
_isNewRefreshHere = false;
_control.Invoke(() =>
{
AddItems(items);
for (int i = 0; i < _guiItems.Count && !_isNewRefreshHere; i++)
{
_guiItems[i].Propriety = ComputePropriety(_guiItems[i]);
}
_refresher.Set();
});
}
那是:
如果我是你,我将尝试创建一个线程安全的等待计数器。 您可以使用诸如Increment和Decrement之类的互锁方法。 这些基本上所做的是将它们作为原子操作递增该值,这被认为是线程安全的。 因此,您可以在调用调用之前增加变量。 这将使您知道等待队列中有多少个线程。 您可以在for循环完成之后以及Invoke块结束之前减小变量。 然后,您可以在for语句中检查等待线程的数量,如果数量大于1,则断开for。这样,您应该确切地知道执行链中有多少个线程。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.