如果另一个线程进入,则退出循环

时间:2013-10-03 07:26:22

标签: c# .net multithreading thread-safety

我遇到了多线程问题。

我有一个方法被调用来对几个项目进行刷新。

在这个方法中,我迭代一个项目列表并刷新其中一个属性。

列表中有很多元素,我们必须做一些数学运算来计算它的属性。

此操作的当前代码如下所示:

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;,在进入Invoke之前设置为true,然后检查Invoke,我不保证在我之前还没有两个调用已经到达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]);
        }
    });
}

这似乎非常好用

2 个答案:

答案 0 :(得分:1)

我会按以下方式进行:

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();
    });
}

那是:

  • 您始终可以使用新的更新取消当前更新。
  • 您不能一次排队多个更新。
  • 保证您没有交叉线程冲突。
  • 你应该测试那段代码,因为我没有。 :)

答案 1 :(得分:1)

如果我是你,我会尝试制作一个线程安全的等待计数器。您可以使用增量和减量等Interlocked方法。这些基本上做的是它们将值增加为原子操作,这被认为是线程安全的。所以你在Invoke调用之前增加变量。这将允许您知道等待队列中有多少个线程。在for循环结束后和Invoke块结束之前递减变量。然后,您可以在for语句中检查等待线程的数量,如果数字大于1则中断for。这样您就应该知道执行链中确切的线程数。