1

マルチスレッドの問題があります。

いくつかのアイテムを更新するために呼び出されるメソッドがあります。

このメソッドでは、アイテムのリストを繰り返し処理し、そのプロパティの 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」ループ内のすべてに関して、直後に実行されることがわかっている場合は問題なく中止できます。

しかし、これをスレッドセーフな方法で行うにはどうすればよいでしょうか?

Invoke に入る前にprivate bool _isNewRefreshHere;, を true に設定してからInvokeチェックインすると、 for ループでチェックする前に Invoke に到達した 2 つの呼び出しが存在しないという保証はありません。

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 に答える