C#でワーカースレッド+キューの基本パターンを試す。

コンピュータ

ワーカースレッドとキューの動きを確認するために、コンソールで入力した文字をコンソールに出力するだけのサンプルコードを作成しました。
コンソールプロジェクトで作成していますが、多分WinFormsやWPFでも動くと思われます。

ファイル名:BasicWorkerQueue.cs

using System.Collections.Concurrent;

namespace WorkerQueSample01;
public class BasicWorkerQueue : IDisposable
{
    private readonly BlockingCollection<string> _queue = [];
    private CancellationTokenSource? _cts;
    private Task? _workerTask;

    public void Start()
    {
        if (_workerTask is not null && !_workerTask.IsCompleted) return; // 多重実行の禁止

        _cts = new CancellationTokenSource();
        _workerTask = Task.Run(() => Worker(_cts.Token));
    }

    public void Enqueue(string item)
    {
        if (!_queue.IsAddingCompleted)
            _queue.Add(item);
    }

    public void Stop()
    {
        _queue.CompleteAdding();
        _cts?.Cancel();

        try
        {
            _workerTask?.Wait();
        }
        catch (AggregateException ae) when (ae.InnerException is OperationCanceledException)
        {
            Console.WriteLine($"[Worker TID:{Environment.CurrentManagedThreadId}] キャンセルを検知しました。");
        }
    }

    private void Worker(CancellationToken token)
    {
        try
        {
            foreach (var item in _queue.GetConsumingEnumerable(token))
            {
                Console.WriteLine($"[Worker TID:{Environment.CurrentManagedThreadId}] {item}");
            }
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine($"[Worker TID:{Environment.CurrentManagedThreadId}] キャンセルされました。");
        }
    }

    public void Dispose()
    {
        Stop();
        _cts?.Dispose();
        _queue.Dispose();
    }
}

ファイル名:Program.cs

namespace WorkerQueSample01;
class Program
{
    static void Main()
    {
        using var workerQueue = new BasicWorkerQueue();
        workerQueue.Start();

        Console.WriteLine($"[Main TID:{Environment.CurrentManagedThreadId}]文字列を入力してください(exitで終了):");

        while (true)
        {
            string? input = Console.ReadLine();
            if (input is null) continue;
            if (input == "exit") break;

            workerQueue.Enqueue(input);
        }

        workerQueue.Stop();
    }
}

ワーカースレッドは、投げっぱなしのタスクでキューからリクエストを取り出し処理を行うループ構造になっており、メインスレッド(UIなど)からはキューにリクエストを登録することでワーカースレッドに仕事(処理)してもらう仕組みとなっています。
投げっぱなしのタスクで、無限ループですのでキャンセルのための機構も備えており、アプリの終了時にはキャンセル機構を使い、無限ループの停止と投げっぱなしだったタスクの開放が必要となります。

コメント