1

我有一个多线程问题。

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

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

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

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

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 之前将 a , 设置为 true ,然后签入Invoke,我不保证在我在 for 循环中检查之前没有两个调用已经到达 Invoke 。

那么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]);
        }
    });
}

这似乎工作得很好

4

2 回答 2

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

那是:

  • 您始终可以使用新的更新取消当前更新。
  • 您一次不能排队多个更新。
  • 保证您没有跨线程冲突。
  • 您应该测试该代码,因为我没有。:)
于 2013-10-03T07:54:55.487 回答
1

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

于 2013-10-03T08:01:29.933 回答