【发布时间】:2020-09-11 23:10:36
【问题描述】:
我正在尝试运行 Windows 服务。该服务应使用工作对象来生成多个任务。
我在工作对象和每个任务中都使用SemaphoreSlim 来等待事件完成,如下所示:
public static IHostBuilder ConfigureServices(this IHostBuilder builder)
{
builder.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<WorkerService>();
services.AddSingleton<WorkerClient>();
});
return builder;
}
工人服务
public WorkerService(ILogger<WorkerService> logger, WorkerClient workerClient)
{
_logger = logger;
_workerClient = workerClient;
_bleClient.OnValuesReceived += _bleClient_OnValuesReceived;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
await _workerClient.Run();
}
catch(Exception ex)
{
_logger.LogCritical(ex, "Error while running worker client.");
}
await Task.Delay(TimeSpan.FromSeconds(_scanDelay), stoppingToken);
}
}
工人客户端
public class WorkerClient
{
private Scanner _scanner;
private SemaphoreSlim _lock;
public WorkerClient()
{
_lock = new SemaphoreSlim(0, 1);
_scanner = new Scanner();
_scanner.OnScanFinished += scanner_ScanFinished;
}
public async Task Run()
{
_scanner.Scan();
await _lock.WaitAsync();
}
private void scanner_ScanFinished(object sender, string[] macs)
{
var tasks = new List<Task>();
foreach(var mac in macs)
{
var client = new TaskRunner(mac);
tasks.Add(client.Run());
}
if(tasks.Count > 0)
{
try
{
var task = Task.WhenAll(tasks.ToArray());
await task;
}
catch(Exception ex)
{
_logger.LogError(ex, ex.Message);
}
}
_lock.Release();
}
}
任务运行器
public class TaskRunner
{
private SemaphoreSlim _lock;
private Client _client;
public TaskRunner(string mac)
{
_lock = new SemaphoreSlim(0, 1);
_client = new Client(mac);
_client.OnWorkFinished += client_WorkFinished;
}
public async Task Run()
{
_client.DoWork();
await _lock.WaitAsync();
}
private void client_WorkFinished(object sender, EventArgs args)
{
_lock.Release();
}
}
当我在控制台或 VS 中启动它时,整个构造运行良好。但是当我使用sc 实用程序创建服务并启动它时,它会在运行 1-2 次后挂起。
我不知道自己做错了什么,因为我对 Windows 服务和多线程非常陌生。
【问题讨论】:
-
只是一些建议。放下代码墙使得很难注意到首屏下方的代码。试着把它分解,这样那些阅读者就可以很容易地看到所涉及的不同领域/类。
-
附带说明,您可以将
while (!stoppingToken.IsCancellationRequested)行替换为while(true),以获得一致的取消行为。让Task.Delay完成取消工作!
标签: c# multithreading windows-services backgroundworker asp.net-core-3.1