3

.Net 4.0 フレームワークで C# を使用すると、ファイルシステム イベントを待機し、それらのイベントによって提供されるファイルに対して事前定義された処理を開始する必要がある Windows フォームのメイン スレッド (これまでのところ唯一のもの) があります。

私は次のことを計画しています:

  • A1. メインプロセスの開始時にすぐに別のスレッドを作成するには;
  • A2. 処理するファイル名をキュー (FIFO) に入れるメイン スレッドを用意します。
  • A3. n 秒ごとにタイマーによって新しいスレッドがトリガーされるようにします。
  • A4. 処理を実行する項目がある場合は、新しいスレッドにキューを読み取らせ、処理したばかりのキュー項目をキャンセルさせます。

私は以前にスレッドをプログラムしたことがないため (基本的に Albahari をコンパスとして使用しています)、間違いなくそうしたいと思っています。

  • Q1. メイン プロセスが書き込みのみを行い、新しいプロセスがキュー アイテムのみをキャンセルする場合、キューで同時実行の問題が発生する可能性がありますか? 言い換えれば、この場合、同期は重要な問題ですか?
  • Q2. 新しいスレッドを最初から作成したり、既存のプールから利用できるスレッドの 1 つを再利用したりできることを確認しました。このコンテキストでプールからスレッドを使用する方が安全/簡単ですか?
  • Q3. 新しいスレッドを無期限に維持し、メイン プロセスが閉じられるまでタイマーのみに応答することに欠点はありますか?
4

1 に答える 1

2

.Net Framework 4をターゲットにしている場合、BlockingCollectionは問題を解決するように思われます。つまり、「作業」アイテムがキューで使用可能になったときに(新しいファイルが追加されたときにイベントハンドラーのキューに追加された)新しいスレッドプールスレッドを作成し、そのスレッドで非同期に処理します。

プロデューサー/コンシューマーキューで使用できます。

例えば:

/// <summary>
/// Producer/consumer queue. Used when a task needs executing, it’s enqueued to ensure order, 
/// allowing the caller to get on with other things. The number of consumers can be defined, 
/// each running on a thread pool task thread. 
/// Adapted from: http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT
/// </summary>
public class ProducerConsumerQueue : IDisposable
{
    private BlockingCollection<Action> _taskQ = new BlockingCollection<Action>();

    public ProducerConsumerQueue(int workerCount)
    {
        // Create and start a separate Task for each consumer:
        for (int i = 0; i < workerCount; i++)
        {
            Task.Factory.StartNew(Consume);
        }
    }

    public void Dispose() 
    { 
        _taskQ.CompleteAdding(); 
    }

    public void EnqueueTask(Action action) 
    { 
        _taskQ.Add(action); 
    }

    private void Consume()
    {
        // This sequence that we’re enumerating will block when no elements
        // are available and will end when CompleteAdding is called.
        // Note: This removes AND returns items from the collection.
        foreach (Action action in _taskQ.GetConsumingEnumerable())
        {
            // Perform task.
            action();
        }
    }
}
于 2012-10-12T10:42:41.377 に答える