From f8b016ac4a99f96243e8d3f74e5f733c7adf4f7f Mon Sep 17 00:00:00 2001 From: luosheng Date: Sat, 11 Feb 2023 10:53:12 +0800 Subject: [PATCH] Remove TaskManager --- Modbus.Net/Modbus.Net.sln | 19 +- Modbus.Net/Modbus.Net/Task/TaskManager.cs | 1162 ----------------- .../Modbus.Net.Modbus.Test.csproj | 4 +- .../Modbus.Net.Modbus.Test/Program.cs | 0 .../Modbus.Net.PersistedTests.csproj | 18 - Tests/Modbus.Net.PersistedTests/Program.cs | 156 --- .../Properties/launchSettings.json | 8 - Tests/Modbus.Net.Tests/BaseTest.cs | 32 - Tests/Modbus.Net.Tests/TaskManagerTest.cs | 150 --- 9 files changed, 8 insertions(+), 1541 deletions(-) delete mode 100644 Modbus.Net/Modbus.Net/Task/TaskManager.cs rename {Modbus.Net => Samples}/Modbus.Net.Modbus.Test/Modbus.Net.Modbus.Test.csproj (67%) rename {Modbus.Net => Samples}/Modbus.Net.Modbus.Test/Program.cs (100%) delete mode 100644 Tests/Modbus.Net.PersistedTests/Modbus.Net.PersistedTests.csproj delete mode 100644 Tests/Modbus.Net.PersistedTests/Program.cs delete mode 100644 Tests/Modbus.Net.PersistedTests/Properties/launchSettings.json delete mode 100644 Tests/Modbus.Net.Tests/TaskManagerTest.cs diff --git a/Modbus.Net/Modbus.Net.sln b/Modbus.Net/Modbus.Net.sln index 3199b4c..26be6b5 100644 --- a/Modbus.Net/Modbus.Net.sln +++ b/Modbus.Net/Modbus.Net.sln @@ -18,11 +18,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D8DD32FC EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Modbus.Net.Tests", "..\Tests\Modbus.Net.Tests\Modbus.Net.Tests.csproj", "{3BB01E98-3D45-454A-A1BD-49D7B2C83B74}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Modbus.Net.PersistedTests", "..\Tests\Modbus.Net.PersistedTests\Modbus.Net.PersistedTests.csproj", "{EC184EF4-81C4-4A4B-8763-79AC4150E613}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{3597B5C5-45B9-4ECB-92A3-D0FFBE47920A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Modbus.Net.Modbus.Test", "Modbus.Net.Modbus.Test\Modbus.Net.Modbus.Test.csproj", "{3615E574-1A98-4BBC-8C08-01FE95AD40AF}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Modbus.Net.Modbus.Test", "..\Samples\Modbus.Net.Modbus.Test\Modbus.Net.Modbus.Test.csproj", "{22A35CA8-CDCF-416D-BA84-08C933B4A3DE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -46,22 +44,17 @@ Global {3BB01E98-3D45-454A-A1BD-49D7B2C83B74}.Debug|Any CPU.Build.0 = Debug|Any CPU {3BB01E98-3D45-454A-A1BD-49D7B2C83B74}.Release|Any CPU.ActiveCfg = Release|Any CPU {3BB01E98-3D45-454A-A1BD-49D7B2C83B74}.Release|Any CPU.Build.0 = Release|Any CPU - {EC184EF4-81C4-4A4B-8763-79AC4150E613}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EC184EF4-81C4-4A4B-8763-79AC4150E613}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EC184EF4-81C4-4A4B-8763-79AC4150E613}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EC184EF4-81C4-4A4B-8763-79AC4150E613}.Release|Any CPU.Build.0 = Release|Any CPU - {3615E574-1A98-4BBC-8C08-01FE95AD40AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3615E574-1A98-4BBC-8C08-01FE95AD40AF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3615E574-1A98-4BBC-8C08-01FE95AD40AF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3615E574-1A98-4BBC-8C08-01FE95AD40AF}.Release|Any CPU.Build.0 = Release|Any CPU + {22A35CA8-CDCF-416D-BA84-08C933B4A3DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22A35CA8-CDCF-416D-BA84-08C933B4A3DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22A35CA8-CDCF-416D-BA84-08C933B4A3DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22A35CA8-CDCF-416D-BA84-08C933B4A3DE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {3BB01E98-3D45-454A-A1BD-49D7B2C83B74} = {D8DD32FC-CF39-4A1A-8FBF-9E82C5278C34} - {EC184EF4-81C4-4A4B-8763-79AC4150E613} = {D8DD32FC-CF39-4A1A-8FBF-9E82C5278C34} - {3615E574-1A98-4BBC-8C08-01FE95AD40AF} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A} + {22A35CA8-CDCF-416D-BA84-08C933B4A3DE} = {3597B5C5-45B9-4ECB-92A3-D0FFBE47920A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AF00D64E-3C70-474A-8A81-E9E48017C4B5} diff --git a/Modbus.Net/Modbus.Net/Task/TaskManager.cs b/Modbus.Net/Modbus.Net/Task/TaskManager.cs deleted file mode 100644 index 8b20615..0000000 --- a/Modbus.Net/Modbus.Net/Task/TaskManager.cs +++ /dev/null @@ -1,1162 +0,0 @@ -/* - * LimitedConcurrencyLevelTaskScheduler类来自于MSDN官方样例,Modbus.Net的作者不保留对这个类的版权。 - * LimitedConcurrencyLevelTaskScheduler class comes from offical samples of MSDN, the author of "Modbus.Net" "donnot" obtain the copyright of LimitedConcurrencyLevelTaskScheduler(only). - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Serilog; -using Modbus.Net.Interface; - -namespace Modbus.Net -{ - /// - /// 返回结果的定义类 - /// - public class DataReturnDef : DataReturnDef - { - } - - /// - /// 返回结果的定义类 - /// - public class DataReturnDef where TMachineKey : IEquatable - { - /// - /// 设备的Id - /// - public TMachineKey MachineId { get; set; } - - /// - /// 返回的数据值 - /// - public Dictionary ReturnValues { get; set; } - } - - /// - /// Limited concurrency level task scheduler - /// - public class LimitedConcurrencyLevelTaskScheduler : TaskScheduler - { - /// - /// Whether the current thread is processing work items. - /// - [ThreadStatic] private static bool _currentThreadIsProcessingItems; - - /// - /// The maximum concurrency level allowed by this scheduler. - /// - private readonly int _maxDegreeOfParallelism; - - /// - /// The list of tasks to be executed. - /// - private readonly LinkedList _tasks = new LinkedList(); // protected by lock(_tasks) - - /// - /// Whether the scheduler is currently processing work items. - /// - private int _delegatesQueuedOrRunning; // protected by lock(_tasks) - - /// - /// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the - /// specified degree of parallelism. - /// - /// - /// The maximum degree of parallelism provided by this scheduler. - /// - public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism) - { - if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism"); - _maxDegreeOfParallelism = maxDegreeOfParallelism; - } - - /// - /// Gets the maximum concurrency level supported by this scheduler. - /// - public sealed override int MaximumConcurrencyLevel - { - get { return _maxDegreeOfParallelism; } - } - - /// - /// Queues a task to the scheduler. - /// - /// - /// The task to be queued. - /// - protected sealed override void QueueTask(Task task) - { - // Add the task to the list of tasks to be processed. If there aren't enough - // delegates currently queued or running to process tasks, schedule another. - lock (_tasks) - { - _tasks.AddLast(task); - if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism) - { - ++_delegatesQueuedOrRunning; - NotifyThreadPoolOfPendingWork(); - } - } - } - - /// - /// Informs the ThreadPool that there's work to be executed for this scheduler. - /// - private void NotifyThreadPoolOfPendingWork() - { - ThreadPool.UnsafeQueueUserWorkItem(_ => - { - // Note that the current thread is now processing work items. - // This is necessary to enable inlining of tasks into this thread. - _currentThreadIsProcessingItems = true; - try - { - // Process all available items in the queue. - while (true) - { - Task item; - lock (_tasks) - { - // When there are no more items to be processed, - // note that we're done processing, and get out. - if (_tasks.Count == 0) - { - --_delegatesQueuedOrRunning; - break; - } - - // Get the next item from the queue - item = _tasks.First.Value; - _tasks.RemoveFirst(); - } - - // Execute the task we pulled out of the queue - TryExecuteTask(item); - } - } - // We're done processing items on the current thread - finally - { - _currentThreadIsProcessingItems = false; - } - }, null); - } - - /// Attempts to execute the specified task on the current thread. - /// The task to be executed. - /// - /// Whether the task could be executed on the current thread. - protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) - { - // If this thread isn't already processing a task, we don't support inlining - if (!_currentThreadIsProcessingItems) return false; - - // If the task was previously queued, remove it from the queue - if (taskWasPreviouslyQueued) TryDequeue(task); - - // Try to run the task. - return TryExecuteTask(task); - } - - /// - /// Attempts to remove a previously scheduled task from the scheduler. - /// - /// - /// The task to be removed. - /// - /// - /// Whether the task could be found and removed. - /// - protected sealed override bool TryDequeue(Task task) - { - lock (_tasks) - { - return _tasks.Remove(task); - } - } - - /// - /// Gets an enumerable of the tasks currently scheduled on this scheduler. - /// - /// - /// An enumerable of the tasks currently scheduled. - /// - protected sealed override IEnumerable GetScheduledTasks() - { - var lockTaken = false; - try - { - Monitor.TryEnter(_tasks, ref lockTaken); - if (lockTaken) return _tasks.ToArray(); - else throw new NotSupportedException(); - } - finally - { - if (lockTaken) Monitor.Exit(_tasks); - } - } - } - - /// - /// 具有任务管理的设备 - /// - /// 设备的Id类型 - public class TaskMachine where TMachineKey : IEquatable - { - /// - /// 任务工厂 - /// - private readonly TaskFactory _tasks; - - /// - /// 构造函数 - /// - /// 设备 - /// 任务工厂 - public TaskMachine(IMachineProperty machine, TaskFactory taskFactory) - { - Machine = machine; - _tasks = taskFactory; - TasksWithTimer = new List(); - } - - /// - /// 设备 - /// - public IMachineProperty Machine { get; } - - /// - /// 任务调度器 - /// - public List TasksWithTimer { get; } - - /// - /// 定时方式启动任务 - /// - /// 任务返回值的类型 - /// 任务 - /// 任务是否执行成功 - public bool InvokeTimer(TaskItem task) - { - task.DetectConnected = () => Machine.IsConnected; - task.GetMachine = () => Machine; - task.GetTaskFactory = () => _tasks; - - - if (!TasksWithTimer.Exists(taskCon => taskCon.Name == task.Name)) - { - lock (TasksWithTimer) - { - TasksWithTimer.Add(task); - } - task.StartTimer(); - return true; - } - return false; - } - - /// - /// 停止任务 - /// - /// 任务的名称 - /// 是否停止成功 - public bool StopTimer(string taskItemName) - { - if (TasksWithTimer.Exists(taskCon => taskCon.Name == taskItemName)) - { - var task = TasksWithTimer.FirstOrDefault(taskCon => taskCon.Name == taskItemName); - task?.StopTimer(); - lock (TasksWithTimer) - { - TasksWithTimer.Remove(task); - } - return true; - } - return false; - } - - /// - /// 停止所有任务 - /// - /// 是否停止成功 - public bool StopAllTimers() - { - var ans = true; - lock (TasksWithTimer) - { - for (int i = 0; i < TasksWithTimer.Count; i++) - { - ans = ans && StopTimer(TasksWithTimer[0].Name); - } - } - return ans; - } - - /// - /// 暂时任务 - /// - /// 任务的名称 - /// 是否暂停成功 - public bool PauseTimer(string taskItemName) - { - if (TasksWithTimer.Exists(taskCon => taskCon.Name == taskItemName)) - { - var task = TasksWithTimer.FirstOrDefault(taskCon => taskCon.Name == taskItemName); - task?.StopTimer(); - return true; - } - return false; - } - - /// - /// 暂停所有任务 - /// - /// 是否暂停成功 - public bool PauseAllTimers() - { - var ans = true; - lock (TasksWithTimer) - { - for (int i = 0; i < TasksWithTimer.Count; i++) - { - ans = ans && PauseTimer(TasksWithTimer[i].Name); - } - } - return ans; - } - - /// - /// 恢复任务 - /// - /// 任务的名称 - /// 是否恢复任务 - public bool ContinueTimer(string taskItemName) - { - if (TasksWithTimer.Exists(taskCon => taskCon.Name == taskItemName)) - { - var task = TasksWithTimer.FirstOrDefault(taskCon => taskCon.Name == taskItemName); - task?.StartTimer(); - return true; - } - return false; - } - - /// - /// 恢复所有任务 - /// - /// 是否恢复成功 - public bool ContinueAllTimers() - { - var ans = true; - lock (TasksWithTimer) - { - foreach (var task in TasksWithTimer) - ans = ans && ContinueTimer(task.Name); - } - return ans; - } - - /// - /// 执行任务一次 - /// - /// 任务返回值的类型 - /// 任务 - /// 任务是否执行成功 - public async Task InvokeOnce(TaskItem task) - { - var ans = await task.Invoke(Machine, _tasks, task.Params?.Invoke(), task.TimeoutTime); - task.Return?.Invoke(ans); - return true; - } - } - - internal class TaskMachineEqualityComparer : IEqualityComparer> - where TKey : IEquatable - { - public bool Equals(TaskMachine x, TaskMachine y) - { - return x.Machine.Id.Equals(y.Machine.Id); - } - - public int GetHashCode(TaskMachine obj) - { - return obj.GetHashCode(); - } - } - - /// - /// 任务的接口 - /// - public interface ITaskItem - { - /// - /// 任务的名称 - /// - string Name { get; set; } - - /// - /// 启动计时器 - /// - /// - bool StartTimer(); - - /// - /// 停止计时器 - /// - /// - bool StopTimer(); - } - - /// - /// 获取数据的预定义任务 - /// - public class TaskItemGetData : TaskItem - { - /// - /// 构造函数 - /// - /// 返回值的处理函数 - /// 返回值的键类型 - /// 任务的超时时间 - /// 重命名,对单个设备使用多个GetData时必须填写不同的字符串 - public TaskItemGetData(Action returnFunc, MachineGetDataType getDataType, int timeout = 100000, string reName = null) - { - Name = reName ?? "GetDatas"; - TimeoutTime = timeout; - Invoke = async (machine, tasks, parameters, timeoutTime) => - { - var cts = new CancellationTokenSource(); - cts.CancelAfter(TimeSpan.FromMilliseconds(timeoutTime)); - try - { - var ans = - await tasks.StartNew( - async () => await machine.GetMachineMethods() - .GetDatasAsync( - getDataType).WithCancellation(cts.Token)).Unwrap(); - return new DataReturnDef - { - MachineId = machine.GetMachineIdString(), - ReturnValues = ans - }; - } - catch (Exception e) - { - Log.Error(e, "GetData task has been canceled."); - machine.Disconnect(); - } - return null; - - }; - Params = null; - Return = returnFunc; - } - - /// - /// 构造函数 - /// - /// 返回值的处理函数 - /// 返回值的键类型 - /// 循环间隔(毫秒) - /// 设备离线时的循环间隔(毫秒) - /// 任务的超时时间 - /// 重命名,对单个设备使用多个GetData时必须填写不同的字符串 - public TaskItemGetData(Action returnFunc, MachineGetDataType getDataType, int getCycle, - int sleepCycle, int timeout = 100000, string reName = null) : this(returnFunc, getDataType, timeout, reName) - { - TimerDisconnectedTime = sleepCycle; - TimerTime = getCycle; - } - } - - /// - /// 写入数据的预定义任务 - /// - public class TaskItemSetData : TaskItem - { - /// - /// 构造函数 - /// - /// 写入的值 - /// 写入值的键类型 - /// 返回值的处理函数 - /// 任务的超时时间 - /// 重命名,对单个设备使用多个GetData时必须填写不同的字符串 - public TaskItemSetData(Func> values, MachineSetDataType setDataType, int timeout = 100000, Action returnFunc = null, string reName = null) - { - Name = reName ?? "SetDatas"; - TimeoutTime = timeout; - Invoke = async (machine, tasks, parameters, timeoutTime) => - { - var cts = new CancellationTokenSource(); - cts.CancelAfter(TimeSpan.FromMilliseconds(timeoutTime)); - try - { - var ans = - await tasks.StartNew( - async () => await machine.GetMachineMethods(). - SetDatasAsync(setDataType, (Dictionary)parameters[0] - ).WithCancellation(cts.Token)).Unwrap(); - return ans; - } - catch (Exception e) - { - Log.Error(e, "SetData task has been canceled."); - machine.Disconnect(); - } - return false; - }; - Params = () => new object[] {values()}; - Return = returnFunc; - } - - /// - /// 构造函数 - /// - /// 写入的值 - /// 写入值的键类型 - /// 返回值的处理函数 - /// 循环间隔(毫秒) - /// 设备离线时的循环间隔(毫秒) - /// 任务的超时时间 - /// 重命名,对单个设备使用多个GetData时必须填写不同的字符串 - public TaskItemSetData(Func> values, MachineSetDataType setDataType, int getCycle, - int sleepCycle, int timeout = 100000, Action returnFunc = null, string reName = null) - : this(values, setDataType, timeout, returnFunc, reName) - { - TimerDisconnectedTime = sleepCycle; - TimerTime = getCycle; - } - } - - /// - /// 任务 - /// - /// 任务返回值的类型 - public class TaskItem : ITaskItem, IEquatable> - { - /// - /// 定时器 - /// - private Timer Timer { get; set; } - - /// - /// 定时器的时间 - /// - public int TimerTime { get; set; } - - /// - /// 超时时间 - /// - public int TimeoutTime { get; set; } = 100000; - - /// - /// 离线定时器 - /// - private Timer TimerDisconnected { get; set; } - - /// - /// 离线定时器的时间 - /// - public int TimerDisconnectedTime { get; set; } - - /// - /// 执行的任务 - /// - public Func> Invoke { get; set; } - - /// - /// 检测设备的在线状态 - /// - internal Func DetectConnected { get; set; } - - /// - /// 任务执行的参数 - /// - public Func Params { get; set; } - - /// - /// 返回值的处理函数 - /// - public Action Return { get; set; } - - /// - /// 获取设备 - /// - internal Func GetMachine { get; set; } - - /// - /// 获取任务工厂 - /// - internal Func GetTaskFactory { get; set; } - - /// - /// 是否相等 - /// - /// 另一个实例 - /// 是否相等 - public bool Equals(TaskItem other) - { - return Name == other?.Name; - } - - /// - /// 名称 - /// - public string Name { get; set; } - - /// - /// 启动定时器 - /// - /// 是否成功 - public bool StartTimer() - { - ActivateTimerDisconnected(); - return true; - } - - /// - /// 停止定时器 - /// - /// - public bool StopTimer() - { - DeactivateTimer(); - DeactivateTimerDisconnected(); - return true; - } - - /// - /// 激活定时器 - /// - private void ActivateTimer() - { - Timer = new Timer(async state => - { - if (!DetectConnected()) TimerChangeToDisconnect(); - var ans = await Invoke(GetMachine(), GetTaskFactory(), Params?.Invoke(), TimeoutTime); - Return?.Invoke(ans); - }, null, 0, TimerTime); - } - - /// - /// 反激活定时器 - /// - private void DeactivateTimer() - { - Timer?.Dispose(); - Timer = null; - } - - /// - /// 激活离线定时器 - /// - private void ActivateTimerDisconnected() - { - TimerDisconnected = new Timer(async state => - { - await GetMachine().ConnectAsync(); - if (DetectConnected()) TimerChangeToConnect(); - }, null, 0, TimerDisconnectedTime); - } - - /// - /// 反激活离线定时器 - /// - private void DeactivateTimerDisconnected() - { - TimerDisconnected?.Dispose(); - TimerDisconnected = null; - } - - /// - /// 将定时器切换至在线 - /// - /// - private bool TimerChangeToConnect() - { - DeactivateTimerDisconnected(); - ActivateTimer(); - return true; - } - - /// - /// 将定时器切换至离线 - /// - /// - private bool TimerChangeToDisconnect() - { - DeactivateTimer(); - ActivateTimerDisconnected(); - return true; - } - - /// - /// 拷贝实例 - /// - /// 拷贝的实例 - public TaskItem Clone() - { - return MemberwiseClone() as TaskItem; - } - } - - /// - /// 任务调度器 - /// - public class TaskManager : TaskManager - { - /// - /// 构造一个TaskManager - /// - /// 同时可以运行的任务数 - /// 读取数据后是否保持连接 - public TaskManager(int maxRunningTask, bool keepConnect) - : base(maxRunningTask, keepConnect) - { - } - - /// - /// 添加一台设备 - /// - /// 设备 - public void AddMachine(BaseMachine machine) - { - base.AddMachine(machine); - } - - /// - /// 添加多台设备 - /// - /// 多台设备 - public void AddMachines(IEnumerable machines) - { - base.AddMachines(machines); - } - - /// - /// 通过Id获取设备 - /// - /// 设备Id - /// 获取的设备 - public new BaseMachine GetMachineById(string id) - { - return base.GetMachineById(id) as BaseMachine; - } - - /// - /// 通过通讯标志获取设备 - /// - /// 通讯标志 - /// 获取的设备 - public new BaseMachine GetMachineByConnectionToken(string connectionToken) - { - return base.GetMachineByConnectionToken(connectionToken) as BaseMachine; - } - } - - /// - /// 任务调度器 - /// - /// 设备Id的类型 - public class TaskManager where TMachineKey : IEquatable - { - /// - /// 正在运行的设备 - /// - private readonly HashSet> _machines; - - /// - /// 全局任务取消标志 - /// - private CancellationTokenSource _cts; - - /// - /// 保持连接 - /// - private bool _keepConnect; - - /// - /// 任务调度 - /// - private TaskScheduler _scheduler; - - /// - /// 任务工厂 - /// - private TaskFactory _tasks; - - /// - /// 构造一个TaskManager - /// - /// 同时可以运行的任务数 - /// 读取数据后是否保持连接 - public TaskManager(int maxRunningTask, bool keepConnect) - { - _scheduler = new LimitedConcurrencyLevelTaskScheduler(maxRunningTask); - _machines = - new HashSet>(new TaskMachineEqualityComparer()); - KeepConnect = keepConnect; - _cts = new CancellationTokenSource(); - _tasks = new TaskFactory(_cts.Token, TaskCreationOptions.None, TaskContinuationOptions.None, _scheduler); - } - - /// - /// 保持连接 - /// - public bool KeepConnect - { - get { return _keepConnect; } - set - { - PauseTimerAll(); - _keepConnect = value; - lock (_machines) - { - foreach (var machine in _machines) - machine.Machine.KeepConnect = _keepConnect; - } - ContinueTimerAll(); - } - } - - /// - /// 最大可执行任务数 - /// - public int MaxRunningTasks - { - get { return _scheduler.MaximumConcurrencyLevel; } - set - { - PauseTimerAll(); - _scheduler = new LimitedConcurrencyLevelTaskScheduler(value); - ContinueTimerAll(); - } - } - - /// - /// 强制停止所有正在运行的任务 - /// - public void TaskHalt() - { - _cts.Cancel(); - _cts = new CancellationTokenSource(); - _tasks = new TaskFactory(_cts.Token, TaskCreationOptions.None, TaskContinuationOptions.None, _scheduler); - } - - /// - /// 添加一台设备 - /// - /// 设备 - public void AddMachine(IMachineProperty machine) - { - machine.KeepConnect = KeepConnect; - lock (_machines) - { - _machines.Add(new TaskMachine(machine, _tasks)); - } - } - - /// - /// 添加多台设备 - /// - /// 设备的列表 - public void AddMachines(IEnumerable> machines) - where TUnitKey : IEquatable - { - foreach (var machine in machines) - AddMachine(machine); - } - - /// - /// 通过Id获取设备 - /// - /// 设备的Id - /// 获取设备 - public IMachineProperty GetMachineById(TMachineKey id) - { - try - { - TaskMachine machine; - lock (_machines) - { - machine = _machines.SingleOrDefault(p => p.Machine.Id.Equals(id)); - } - return machine?.Machine; - } - catch (Exception e) - { - Log.Error(e, $"Device {id} get error, maybe duplicated in taskmanager"); - return null; - } - } - - /// - /// 通过通讯标志获取设备 - /// - /// 通讯标志 - /// 获取的数据 - public IMachineProperty GetMachineByConnectionToken(string connectionToken) - { - try - { - TaskMachine machine; - lock (_machines) - { - machine = _machines.SingleOrDefault(p => p.Machine.ConnectionToken == connectionToken && p.Machine.IsConnected); - } - return machine?.Machine; - } - catch (Exception e) - { - Log.Error(e, $"Device {connectionToken} get error, maybe duplicated in taskmanager"); - return null; - } - } - - /// - /// 根据设备的连接地址移除设备 - /// - /// 设备的连接地址 - public void RemoveMachineWithToken(string machineToken) - { - lock (_machines) - { - _machines.RemoveWhere(p => p.Machine.ConnectionToken == machineToken); - } - } - - /// - /// 根据设备的id移除设备 - /// - /// 设备的id - public void RemoveMachineWithId(TMachineKey id) - { - lock (_machines) - { - _machines.RemoveWhere(p => p.Machine.Id.Equals(id)); - } - } - - /// - /// 移除设备 - /// - /// 设备的实例 - public void RemoveMachine(IMachineProperty machine) - { - lock (_machines) - { - _machines.RemoveWhere(p => p.Machine.Equals(machine)); - } - } - - /// - /// 所有设备执行定时任务 - /// - /// 任务返回值的类型 - /// 任务 - /// 所有任务是否执行成功 - public bool InvokeTimerAll(TaskItem item) - { - var ans = true; - lock (_machines) - { - foreach (var machine in _machines) - { - Thread.Sleep(10); - ans &= machine.InvokeTimer(item.Clone()); - } - } - return ans; - } - - /// - /// 所有设备停止执行所有任务 - /// - /// 所有任务是否停止成功 - public bool StopTimerAll() - { - var ans = true; - lock (_machines) - { - foreach (var machine in _machines) - { - Thread.Sleep(10); - ans &= machine.StopAllTimers(); - } - } - return ans; - } - - /// - /// 所有设备停止执行某一个任务 - /// - /// 任务名称 - /// 任务是否停止成功 - public bool StopTimerAll(string taskItemName) - { - var ans = true; - lock (_machines) - { - foreach (var machine in _machines) - ans &= machine.StopTimer(taskItemName); - } - return ans; - } - - /// - /// 所有设备暂停执行所有任务 - /// - /// 任务是否暂停成功 - public bool PauseTimerAll() - { - var ans = true; - lock (_machines) - { - foreach (var machine in _machines) - ans &= machine.PauseAllTimers(); - } - return ans; - } - - /// - /// 所有设备暂停执行某一个任务 - /// - /// 任务的名称 - /// 任务是否暂停成功 - public bool PauseTimerAll(string taskItemName) - { - var ans = true; - lock (_machines) - { - foreach (var machine in _machines) - ans &= machine.PauseTimer(taskItemName); - } - return ans; - } - - /// - /// 所有设备继续执行所有任务 - /// - /// 所有任务是否继续执行成功 - public bool ContinueTimerAll() - { - var ans = true; - lock (_machines) - { - foreach (var machine in _machines) - ans &= machine.ContinueAllTimers(); - } - return ans; - } - - /// - /// 所有设备继续执行某一个任务 - /// - /// 任务的名称 - /// 任务是否继续执行成功 - public bool ConinueTimerAll(string taskItemName) - { - lock (_machines) - { - foreach (var machine in _machines) - machine.ContinueTimer(taskItemName); - } - return true; - } - - /// - /// 所有设备执行一个一次性任务 - /// - /// 任务的返回值类型 - /// 任务 - /// 任务是否执行成功 - public async Task InvokeOnceAll(TaskItem item) - { - var tasks = new List>(); - lock (_machines) - { - foreach (var machine in _machines) - tasks.Add(_tasks.StartNew(async () => await machine.InvokeOnce(item.Clone())).Unwrap()); - } - var ans = await Task.WhenAll(tasks); - return ans.All(p => p); - } - - /// - /// 某个设备执行一个一次性任务 - /// - /// 任务的返回值类型 - /// 设备的Id - /// 任务 - /// 任务是否执行成功 - public async Task InvokeOnceForMachine(TMachineKey machineId, TaskItem item) - { - var machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(machineId)); - if (machine != null) - return await machine.InvokeOnce(item.Clone()); - return false; - } - - /// - /// 某个设备执行一个定时任务 - /// - /// 任务的返回值类型 - /// 设备的Id - /// 任务 - /// 任务是否执行成功 - public bool InvokeTimerForMachine(TMachineKey machineId, TaskItem item) - { - var machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(machineId)); - if (machine != null) - return machine.InvokeTimer(item.Clone()); - return false; - } - - /// - /// 某个设备停止一个定时任务 - /// - /// 任务的Id - /// 任务的名称 - /// 任务是否停止成功 - public bool StopTimerForMachine(TMachineKey machineId, string taskItemName) - { - var machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(machineId)); - if (machine != null) - return machine.StopTimer(taskItemName); - return false; - } - - /// - /// 某个设备暂停一个定时任务 - /// - /// 任务的Id - /// 任务的名称 - /// 任务是否暂停成功 - public bool PauseTimerForMachine(TMachineKey machineId, string taskItemName) - { - var machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(machineId)); - if (machine != null) - return machine.PauseTimer(taskItemName); - return false; - } - - /// - /// 某个设备继续进行一个定时任务 - /// - /// 任务的Id - /// 任务的名称 - /// 任务是否继续运行成功 - public bool ContinueTimerForMachine(TMachineKey machineId, string taskItemName) - { - var machine = _machines.FirstOrDefault(p => p.Machine.Id.Equals(machineId)); - if (machine != null) - return machine.ContinueTimer(taskItemName); - return false; - } - } -} \ No newline at end of file diff --git a/Modbus.Net/Modbus.Net.Modbus.Test/Modbus.Net.Modbus.Test.csproj b/Samples/Modbus.Net.Modbus.Test/Modbus.Net.Modbus.Test.csproj similarity index 67% rename from Modbus.Net/Modbus.Net.Modbus.Test/Modbus.Net.Modbus.Test.csproj rename to Samples/Modbus.Net.Modbus.Test/Modbus.Net.Modbus.Test.csproj index 03d49b6..baab5a4 100644 --- a/Modbus.Net/Modbus.Net.Modbus.Test/Modbus.Net.Modbus.Test.csproj +++ b/Samples/Modbus.Net.Modbus.Test/Modbus.Net.Modbus.Test.csproj @@ -12,8 +12,8 @@ - - + + diff --git a/Modbus.Net/Modbus.Net.Modbus.Test/Program.cs b/Samples/Modbus.Net.Modbus.Test/Program.cs similarity index 100% rename from Modbus.Net/Modbus.Net.Modbus.Test/Program.cs rename to Samples/Modbus.Net.Modbus.Test/Program.cs diff --git a/Tests/Modbus.Net.PersistedTests/Modbus.Net.PersistedTests.csproj b/Tests/Modbus.Net.PersistedTests/Modbus.Net.PersistedTests.csproj deleted file mode 100644 index f430833..0000000 --- a/Tests/Modbus.Net.PersistedTests/Modbus.Net.PersistedTests.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - Exe - net6.0 - - - - - - - - - - - - - diff --git a/Tests/Modbus.Net.PersistedTests/Program.cs b/Tests/Modbus.Net.PersistedTests/Program.cs deleted file mode 100644 index b7d3578..0000000 --- a/Tests/Modbus.Net.PersistedTests/Program.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using Modbus.Net.Modbus; -using Modbus.Net.Interface; -using Serilog; - -namespace Modbus.Net.PersistedTests -{ - class Program - { - static void Main(string[] args) - { - Log.Logger = new LoggerConfiguration().MinimumLevel.Verbose().WriteTo.Console().CreateLogger(); - - IMachineProperty machine = new ModbusMachine(1, ModbusType.Rtu, "COM1", - new List() - { - new AddressUnit() - { - Id = "1", - Area = "4X", - Address = 1, - Name = "test 1", - DataType = typeof(ushort) - }, - new AddressUnit() - { - Id = "2", - Area = "4X", - Address = 2, - Name = "test 2", - DataType = typeof(ushort) - }, - new AddressUnit() - { - Id = "3", - Area = "4X", - Address = 3, - Name = "test 3", - DataType = typeof(ushort) - }, - }, true, 2, 1); - IMachineProperty machine2 = new ModbusMachine(2, ModbusType.Rtu, "COM1", - new List() - { - new AddressUnit() - { - Id = "1", - Area = "4X", - Address = 11, - Name = "test 1", - DataType = typeof(ushort) - }, - new AddressUnit() - { - Id = "2", - Area = "4X", - Address = 12, - Name = "test 2", - DataType = typeof(ushort) - }, - new AddressUnit() - { - Id = "3", - Area = "4X", - Address = 13, - Name = "test 3", - DataType = typeof(ushort) - }, - }, true, 3, 1); - IMachineProperty machine3 = new ModbusMachine(3, ModbusType.Rtu, "COM1", - new List() - { - new AddressUnit() - { - Id = "1", - Area = "4X", - Address = 21, - Name = "test 1", - DataType = typeof(ushort) - }, - new AddressUnit() - { - Id = "2", - Area = "4X", - Address = 22, - Name = "test 2", - DataType = typeof(ushort) - }, - new AddressUnit() - { - Id = "3", - Area = "4X", - Address = 23, - Name = "test 3", - DataType = typeof(ushort) - }, - }, true, 4, 1); - - TaskManager manager = new TaskManager(20, true); - manager.AddMachines(new List> { machine, machine2, machine3 }); - Random r = new Random(); - manager.InvokeTimerForMachine(1, new TaskItemSetData(() => new Dictionary - { - { - "4X 1.0", r.Next() % 65536 - }, - { - "4X 2.0", r.Next() % 65536 - }, - { - "4X 3.0", r.Next() % 65536 - }, - }, MachineSetDataType.Address, 10000, 10000)); - manager.InvokeTimerForMachine(2, new TaskItemSetData(() => new Dictionary - { - { - "4X 11.0", r.Next() % 65536 - }, - { - "4X 12.0", r.Next() % 65536 - }, - { - "4X 13.0", r.Next() % 65536 - }, - }, MachineSetDataType.Address, 10000, 10000)); - manager.InvokeTimerForMachine(3, new TaskItemSetData(() => new Dictionary - { - { - "4X 21.0", r.Next() % 65536 - }, - { - "4X 22.0", r.Next() % 65536 - }, - { - "4X 23.0", r.Next() % 65536 - }, - }, MachineSetDataType.Address, 10000, 10000)); - Thread.Sleep(5000); - manager.InvokeTimerAll(new TaskItemGetData(data => - { - if (data?.ReturnValues != null) - { - foreach (var dataInner in data.ReturnValues) - { - Console.WriteLine(dataInner.Key + " " + dataInner.Value.PlcValue); - } - } - }, MachineGetDataType.Address, 10000, 10000)); - - Console.Read(); - Console.Read(); - } - } -} diff --git a/Tests/Modbus.Net.PersistedTests/Properties/launchSettings.json b/Tests/Modbus.Net.PersistedTests/Properties/launchSettings.json deleted file mode 100644 index 33504c9..0000000 --- a/Tests/Modbus.Net.PersistedTests/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "WSL": { - "commandName": "WSL2", - "distributionName": "" - } - } -} \ No newline at end of file diff --git a/Tests/Modbus.Net.Tests/BaseTest.cs b/Tests/Modbus.Net.Tests/BaseTest.cs index f03cc6f..178c82e 100644 --- a/Tests/Modbus.Net.Tests/BaseTest.cs +++ b/Tests/Modbus.Net.Tests/BaseTest.cs @@ -12,10 +12,6 @@ namespace Modbus.Net.Tests { private List> _addressUnits; - private TaskManager _taskManager; - - private BaseMachine _baseMachine; - private BaseMachine _baseMachine2; [TestInitialize] @@ -129,11 +125,6 @@ namespace Modbus.Net.Tests }, }; - _baseMachine = new ModbusMachine(1, ModbusType.Tcp, "192.168.1.1", _addressUnits, true, 2, 0) - { - ProjectName = "Project 1", - MachineName = "Test 1" - }; _baseMachine2 = new SiemensMachine(2, SiemensType.Tcp, "192.168.3.10", SiemensMachineModel.S7_1200, _addressUnits, true, 2, 0) { ProjectName = "Project 1", @@ -141,11 +132,6 @@ namespace Modbus.Net.Tests }; _baseMachine2.ConnectAsync().Wait(); - - _taskManager = new TaskManager(10, true); - - _taskManager.AddMachine(_baseMachine); - _taskManager.AddMachine(_baseMachine2); } [TestMethod] @@ -307,24 +293,6 @@ namespace Modbus.Net.Tests Assert.AreEqual(combinedAddresses[4].GetCount, 8); } - [TestMethod] - public void TaskManagerGetMachineTest() - { - var machine = _taskManager.GetMachineById(1); - Assert.AreEqual(machine.MachineName, "Test 1"); - - var machine2 = _taskManager.GetMachineByConnectionToken("192.168.3.10"); - Assert.AreEqual(machine2.MachineName, "Test 2"); - } - - [TestMethod] - public void BaseMachineGetAddressTest() - { - var addressUnit = _baseMachine.GetAddressUnitById(1); - Assert.AreEqual(addressUnit.Area, "3X"); - Assert.AreEqual(addressUnit.Address, 1); - } - [TestCleanup] public void MachineClean() { diff --git a/Tests/Modbus.Net.Tests/TaskManagerTest.cs b/Tests/Modbus.Net.Tests/TaskManagerTest.cs deleted file mode 100644 index e16bc71..0000000 --- a/Tests/Modbus.Net.Tests/TaskManagerTest.cs +++ /dev/null @@ -1,150 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Modbus.Net.Modbus; - -namespace Modbus.Net.Tests -{ - [TestClass] - public class TaskManagerTest - { - private TaskManager _taskManager; - - private Dictionary _valueDic = new Dictionary(); - - private Timer _timer; - - [TestInitialize] - public void TaskManagerInit() - { - _taskManager = new TaskManager(20, true); - - var addresses = new List - { - new AddressUnit - { - Id = "0", - Area = "4X", - Address = 2, - SubAddress = 0, - CommunicationTag = "A1", - DataType = typeof(ushort) - }, - new AddressUnit - { - Id = "1", - Area = "4X", - Address = 3, - SubAddress = 0, - CommunicationTag = "A2", - DataType = typeof(ushort) - }, - new AddressUnit - { - Id = "2", - Area = "4X", - Address = 4, - SubAddress = 0, - CommunicationTag = "A3", - DataType = typeof(ushort) - }, - new AddressUnit - { - Id = "3", - Area = "4X", - Address = 5, - SubAddress = 0, - CommunicationTag = "A4", - DataType = typeof(ushort) - }, - new AddressUnit - { - Id = "4", - Area = "4X", - Address = 6, - SubAddress = 0, - CommunicationTag = "A5", - DataType = typeof(uint) - }, - new AddressUnit - { - Id = "5", - Area = "4X", - Address = 8, - SubAddress = 0, - CommunicationTag = "A6", - DataType = typeof(uint) - } - }; - - BaseMachine machine = new ModbusMachine("1", ModbusType.Tcp, "192.168.3.10", addresses, true, 2, 0); - - _taskManager.AddMachine(machine); - - var r = new Random(); - - _timer = new Timer(async state => - { - lock (_valueDic) - { - _valueDic = new Dictionary - { - { - "A1", r.Next(0, UInt16.MaxValue) - }, - { - "A2", r.Next(0, UInt16.MaxValue) - }, - { - "A3", r.Next(0, UInt16.MaxValue) - }, - { - "A4", r.Next(0, UInt16.MaxValue) - }, - { - "A5", r.Next() - }, - { - "A6", r.Next() - } - }; - } - await _taskManager.InvokeOnceAll(new TaskItemSetData(() => _valueDic, MachineSetDataType.CommunicationTag)); - }, null, 0, 5000); - } - - [TestMethod] - public async Task TaskManagerValueReadWriteTest() - { - Thread.Sleep(2000); - - var i = 5; - while (i > 0) - { - Thread.Sleep(5000); - await _taskManager.InvokeOnceAll(new TaskItemGetData( - def => - { - var dicans = def.ReturnValues.ToDictionary(p => p.Key, p => p.Value.PlcValue); - Assert.AreEqual(dicans["A1"], _valueDic["A1"]); - Assert.AreEqual(dicans["A2"], _valueDic["A2"]); - Assert.AreEqual(dicans["A3"], _valueDic["A3"]); - Assert.AreEqual(dicans["A4"], _valueDic["A4"]); - Assert.AreEqual(dicans["A5"], _valueDic["A5"]); - Assert.AreEqual(dicans["A6"], _valueDic["A6"]); - }, MachineGetDataType.CommunicationTag)); - i--; - } - } - - [TestCleanup] - public void TaskManagerFinilize() - { - _taskManager.StopTimerAll(); - _timer.Dispose(); - } - } -}