マルチスレッドの問題があります。
いくつかのアイテムを更新するために呼び出されるメソッドがあります。
このメソッドでは、アイテムのリストを繰り返し処理し、そのプロパティの 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]);
}
});
}
これは非常にうまく機能しているようです