ワーカースレッドとキューの動きを確認するために、コンソールで入力した文字をコンソールに出力するだけのサンプルコードを作成しました。
コンソールプロジェクトで作成していますが、多分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など)からはキューにリクエストを登録することでワーカースレッドに仕事(処理)してもらう仕組みとなっています。
投げっぱなしのタスクで、無限ループですのでキャンセルのための機構も備えており、アプリの終了時にはキャンセル機構を使い、無限ループの停止と投げっぱなしだったタスクの開放が必要となります。
コメント