using Cowain.Base.Helpers; using Plugin.Cowain.Driver.ViewModels; using Microsoft.Extensions.DependencyInjection; using Plugin.Cowain.Driver.Abstractions; using Plugin.Cowain.Driver.IServices; using Microsoft.Extensions.Logging; namespace Plugin.Cowain.Driver; /// /// 设备数据采集,不注入到容器,一个设备一个线程 /// public class DeviceThread { private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); // 初始化计数为1,最大计数也为1,实现互斥 private Task? _mainTask; private Task? _consumeVariablesTask; private readonly IDriver _driver; private readonly DeviceViewModel _device; private readonly IActionPluginService _actionPluginService; private IServiceProvider _serviceProvider; private IVariableChannelService? _variableChannelService; private readonly ILogger _logger; public DeviceViewModel Device { get => _device; } public IDriver Driver { get => _driver; } public DeviceThread(IDriver driver, IActionPluginService actionPluginService, IServiceProvider serviceProvider, DeviceViewModel device) { _serviceProvider = serviceProvider; _driver = driver; _actionPluginService = actionPluginService; _device = device; _variableChannelService = _serviceProvider.GetService(); _logger = ServiceLocator.GetRequiredService>(); } public async Task StartReadAsync(CancellationToken cancellationToken) { if (!_device.Enable) { return; } _logger.LogInformation($"DeviceThread线程自动启动:{_device.DeviceName}"); await _semaphore.WaitAsync(cancellationToken); _variableChannelService?.RegisterDeviceActions(_device); //消费变量,但不等待结果 _consumeVariablesTask = _variableChannelService?.ConsumeVariablesAsync(); _mainTask = Task.Factory.StartNew(async () => { _driver.SetParam(_device.Param); _driver.SetDeviceModel(_device); var connect = await _driver.OpenAsync(); if (!connect) { //建立过链接后就不用再连接了 _logger.LogInformation($"DeviceThread设备连接失败:{_device.DeviceName}"); } await _driver.ReadThreadAsync(_device, cancellationToken); }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap(); //释放信号量,允许其他线程进入 _semaphore.Release(); } public async Task StopReadAsync(CancellationToken cancellationToken) { _logger.LogInformation($"DeviceThread线程停止开始:{_device.DeviceName}"); _variableChannelService?.StopConsumeVariablesAsync(cancellationToken); try { // 等待消费变量任务完成 _logger.LogInformation($"DeviceThread 消费变量任务判断:{_device.DeviceName}"); if (_consumeVariablesTask != null && !_consumeVariablesTask.IsCompleted) { _logger.LogInformation($"DeviceThread 消费变量任务await:{_device.DeviceName}"); await Task.WhenAny(_consumeVariablesTask, Task.Delay(Timeout.Infinite, cancellationToken)); } // 等待主任务完成 _logger.LogInformation($"DeviceThread 主任务判断:{_device.DeviceName}"); if (_mainTask != null && !_mainTask.IsCompleted) { _logger.LogInformation($"DeviceThread 主任务await:{_device.DeviceName}"); await Task.WhenAny(_mainTask, Task.Delay(Timeout.Infinite, cancellationToken)); } } catch (OperationCanceledException ex) { _logger.LogInformation($"DeviceThread-StopReadAsync任务取消:{_device.DeviceName}->{ex.Message}"); } catch (Exception ex) { _logger.LogError(ex, $"DeviceThread-StopReadAsync任务异常:{_device.DeviceName}"); } finally { // 确保资源释放 _driver.Close(); _logger.LogInformation($"DeviceThread线程停止完成:{_device.DeviceName}"); } } }