2016-07-15 17 views
3

を待っています。C#が、私はいくつかのレガシー<em>のWinForms</em>コードをアップグレードしていると私は次のようにリファクタリングする<strong>.NET 4.6.1</strong>のようにどのような「正しい方法」把握しようとしています一覧に<T>カウント

boolプロパティをチェックしている間、現在のコードはタイトなwhile(true)ループを実行しています。このプロパティはlock()を汎用List<T>に置き、項目がない場合はtrueを返します(list.Count == 0)。

ループには、メッセージポンプが処理を続行することを確認するために恐れがあるApplication.DoEvents()が含まれています。そうでない場合、アプリケーションがロックされます。

明らかに、これは必要です。

私の混乱は、キュー上の長さを確認できる基本的なリファクタリングを開始する方法です。スレッドで実行していて、何の理由もなくCPUを吹き飛ばすことはありません。ここでのチェックの間の遅延は、たとえ100ms +のような "長い"ものであっても、問題ありません。

私はメソッドの非同期を行い、チェックを行うには、タスクの実行をすることができますアプローチで行くつもりだった:もちろん

await Task.Run(() => KeepCheckingTheQueue()); 

、これはする必要が方法の状況で私を続けています。.. 。ループを使ってキューの状態を確認する。

このスレッドをスレッドプールに移動するのに使用できる待機中、待機中、およびその他のさまざまな方法...これをどのように処理するのがベストか?

+0

処理のスレッドを開始し、終了するとイベントが発生します。あなたはイベントを処理することができ、loop-> checkstatusの必要はありません。 [バックグラウンドワーカー](https://msdn.microsoft.com/en-us/library/cc221403(v=v1).aspx)に入れ、RunWorkerCompletedイベントを使用する – bansi

+1

リストを置き換えることができますか?例えば、 'ConcurrentQueue '? –

+1

リストタイプの置き換えは可能ですか? 'IList 'を実装した独自のクラスを持たないことができますか?本当のリストが裏付けされていて、 'Remove'がカウントを0にすると(または' Clear'が呼び出されたときに)望ましい動作をトリガーします。 –

答えて

4

私が必要なものか「世論調査」ブールメンバー(またはプロパティ)最高にDoEvents関数なしで、UIを解放しながら、()である。

あなたが求めている答え:

private async Task WaitUntilAsync(Func<bool> func) 
{ 
    while (!func()) 
    await Task.Delay(100); 
} 

await WaitUntilAsync(() => list.Count == 0); 

しかし、このようなポーリングは本当に貧しいのアプローチで、あなたのコードが解決された実際の問題を記述することができるなら、あなたがよりよい解決策を得ることができ

たとえば、リストが作業のキューを表していて、コードが完了するまで非同期に待機したい場合は、明示的な信号(たとえばTaskCompletionSource<T>)または真のプロデューサ/コンシューマキュー例えば、TPLデータフロー)。

+0

これはアプローチIです想像していた(私が持っていたものより優れていたが、同意して、まだ悪い)。 問題をより詳しく説明するために、これはWinFormsの「アニメーション」システムです。「偽のWPF」のようなものです。キューには、アニメーション化されるコントロールのリストが保持されているため、並行して実行できます。 'DoEvents()'は 'Control'キュー(' List <> ')がメッセージをポンピングしながらこれらのアニメーションを"並行して実行 "できるようにしていることをチェックします。私は時間の制約と大きなソースのために、完全で完全なリファクタリングを避けようとしています。 'bool'プロパティは本質的に「all done」で、' queue.Length == 0 'を返します。 – Patrick

+1

@Patrick: 'Task.WhenAll'、' TaskCompletionSource '、または' AsyncCountdownEvent'の使用を検討してください。私は利用可能な[ここ](https://github.com/StephenCleary/AsyncEx.Coordination)のACEを持っています。 –

+0

ありがとう!私は見てみましょう。面白いことに、 'TaskCompletionSource'という言葉は、現在開いているMSDNタブです。 – Patrick

1

クライアントコードでは、クエリを実行する前にコレクションをロックすること(またはlock()ブロックを使用してコードを振りかざすこと)を心配するのは、一般的にはお勧めできません。その複雑さをカプセル化するのがベストです。

代わりにConcurrentBagなどの.NETコンカレントコレクションの1つを使用することをお勧めします。若干高価なTaskを作成する必要はありません。

あなたのコレクションにはあまり変化しないあなたは、このようなImmutableList<>として不変スレッドセーフなコレクションの一つを検討する必要があります場合。

編集:あなたのコメントを読んで、私はあなたがWinForms Timerを使用することをお勧めします。 OnApplicationIdleまたはBackgroundWorkerです。 asyncの問題は、定期的に呼び出す必要があることです。タイマーまたはアプリアイドルコールバックを使用すると、GUIスレッドを使用する利点があります。

+0

ここでの問題は、現在のコードがマルチスレッドではないので、私はすでにロックが使用されていないことを期待しているので、 'lock()'が私の心配ではないことです!私が必要とするのは、DoEvents()を使わずに、UIを解放してブールメンバー(またはプロパティ)を "ポーリング"する最良の方法です。 – Patrick

+0

マルチスレッドでなければ、まず最初に 'lock()'が追加されました。バックグラウンドジョブや 'Task'の必要性がすぐに返ってくるのはなぜですか? – MickyD

+0

私は正確な理由はわかりませんが、明示的なスレッディングコードは使用されていません。 – Patrick

0

ユースケースによっては、バックグラウンドスレッドまたはバックグラウンドワーカーを開始できます。または、おそらくタイマー。

これらは異なるスレッドで実行されるため、他のフォーム関連コードの実行をロックしません。 Invoke UIスレッドでアクションを実行する必要がある場合は元のスレッド。あなたが本当にする必要がある場合

if (list.Count == 0) 
{ 
    lock (lockObject) 
    { 
     if (list.Count == 0) 
     { 
      // execute your code here 
     } 
    } 
} 

あなただけロックされる方法を、あなたはの不必要なブロッキングを避ける:

また、私は実際にロックする前にチェックを行うことにより、例えば、できるだけ多くのロックを防止することをお勧めしますあなたの申請。

+0

スレッド、スレッドプール、およびスレッドを使用して、あまりにも多くのマルチスレッドWinFormsコードを書いていますが、 BackgroundWorkers'を使っていますが、この方法ではループをしっかりとチェックしてから 'bool'をチェックして終了する必要はありませんか?ここでは、Thread.Sleep()しかし、それが最善の方法であれば私はそれをやろうとします。 – Patrick

0

あなたがここにいるのは、await Task.Yield()の能力だと思います。

class TheThing { 
    private readonly List<int> _myList = new List<int>(); 

    public async Task WaitForItToNotBeEmpty() { 
    bool hadItems; 
    do { 
     await Task.Yield(); 
     lock (_myList) // Other answers have touched upon this locking concern 
     hadItems = _myList.Count != 0; 
    } while (!hadItems); 
    } 
    // ... 
} 
関連する問題