C# 的异步任务中, 如何暂停, 继续,停止任务

csharp 复制代码
namespace taskTest
{
    using System;
    using System.Threading;
    using System.Threading.Tasks;

    public class MyService
    {
        private Task? workTask;
        private readonly SemaphoreSlim semaphore = new SemaphoreSlim(0, 1); // 初始为 0,Start() 启动时手动放行
        private readonly CancellationTokenSource cts = new CancellationTokenSource();
        private volatile bool autoReleaseSemaphore = true; // 控制 ProcessAsync 是否自动 Release

        public void Start()
        {
            Console.WriteLine("Starting service");
            autoReleaseSemaphore = true;
            semaphore.Release(); // 初始启动一次
            workTask = Task.Run(() => TreadJob(cts.Token));
            Console.WriteLine("Service started, task ID: " + workTask.Id);
        }

        public void Pause()
        {
            Console.WriteLine("Pausing service...");
            autoReleaseSemaphore = false; // 禁止 ProcessAsync 自动 Release
        }

        public void Resume()
        {
            Console.WriteLine("Resuming service...");
            autoReleaseSemaphore = true; // 允许 ProcessAsync 自动 Release
            semaphore.Release(); // 手动触发一次 Release,唤醒阻塞的 WaitAsync
        }

        public void Stop()
        {
            Console.WriteLine("Stopping service...");
            cts.Cancel();
        }

        private async Task TreadJob(CancellationToken token)
        {
            Console.WriteLine("TreadJob started...");
            try
            {
                if (!cts.IsCancellationRequested)
                {
                    Console.WriteLine("Working...");
                    await ProcessAsync(token);
                }
            }
            catch (OperationCanceledException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine("Service stopped");
            }
        }

        private async Task ProcessAsync(CancellationToken token)
        {
            for (int i = 0; i < 100; i++)
            {
                await semaphore.WaitAsync(token); // 等待信号量
                token.ThrowIfCancellationRequested();
                await Task.Delay(500, token);


                if (autoReleaseSemaphore)
                {
                    semaphore.Release(); // 只有当 autoReleaseSemaphore 为 true 时才 Release
                }
                else
                {
                    continue;
                }
                Console.WriteLine($"Process.{i}");
            }
        }
    }
}
csharp 复制代码
namespace taskTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            MyService service = new();
            service.Start();

            // 等待一段时间,确保 ProcessAsync 有机会执行
            Console.ReadLine();
            //Thread.Sleep(1500);

            // 暂停服务
            service.Pause();
            Console.WriteLine("暂停了");

            Console.WriteLine("按下回车启动Resume");
            Console.ReadLine();
            Console.WriteLine("ReadLine执行完");
            service.Resume();

            Console.ReadLine();

            service.Stop();
            Console.ReadLine();
        }
    }
}

结果:

在PLC中的应用:

csharp 复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using S7.Net;

namespace taskTest
{
    public class S7ConnServiceImpl : IS7ConnService
    {
        public S7ConnServiceImpl(Db95DeviceHis db95DeviceHis)
        {
            this.db95DeviceHis = db95DeviceHis;
        }

        private static readonly object lockObj = new object(); // 创建一个对象作为锁
        private Db95DeviceHis db95DeviceHis;
        private bool myIsConnected = false;
        private int errorTimes = 0;
        private CancellationTokenSource cts = new();
        private readonly SemaphoreSlim semaphore = new SemaphoreSlim(0, 1); // 初始为 0,Start() 启动时手动放行
        private volatile bool autoReleaseSemaphore = true; // 控制 ProcessAsync 是否自动 Release

        public bool MyIsConnected
        {
            get => myIsConnected;
            set => myIsConnected = value;
        }
        private Plc s7Plc = null;
        public Plc S7Plc => s7Plc;

        public void ConnPlc(string myIp, int dbNum, int startByte)
        {
            return;
        }

        public void ConnPlc(string myIp)
        {
            autoReleaseSemaphore = true;
            semaphore.Release(); // 初始启动一次
            try
            {
                Task.Factory.StartNew(
                    async () =>
                    {
                        while (!cts.IsCancellationRequested)
                        {
                            if (s7Plc == null || !MyIsConnected)
                            {
                                try
                                {
                                    s7Plc = new Plc(CpuType.S71500, myIp, 0, 1);
                                    s7Plc.Open();
                                    s7Plc.ReadTimeout = 620;
                                    s7Plc.WriteTimeout = 620;
                                    //ctsRead1 = new();
                                    //ctsRead2 = new();
                                    MyIsConnected = s7Plc.IsConnected;
                                    if (MyIsConnected)
                                    {
                                        Console.WriteLine("PlcSucessConn!");
                                    }
                                }
                                catch (PlcException ex)
                                {
                                    errorTimes++;
                                    s7Plc.Close();
                                    s7Plc = null;
                                    MyIsConnected = false;
                                    Console.WriteLine(ex.Message);
                                    Console.WriteLine("ErrorsTime:" + errorTimes);
                                    await Task.Delay(2000);
                                }
                            }
                            else if (MyIsConnected)
                            {
                                try
                                {
                                    MyIsConnected = s7Plc.IsConnected;
                                    await semaphore.WaitAsync(cts.Token); // 等待信号量
                                    cts.Token.ThrowIfCancellationRequested();
                                    await Task.Delay(200);
                                    errorTimes = 0;

                                    if (autoReleaseSemaphore)
                                    {
                                        semaphore.Release(); // 只有当 autoReleaseSemaphore 为 true 时才 Release
                                    }
                                    else
                                    {
                                        continue;
                                    }


                                    var tempDb95DeviceHis =
                                        await S7Plc.ReadClassAsync<Db95DeviceHis>(95, 0);

                                    lock (lockObj)
                                    {
                                        if (tempDb95DeviceHis != null)
                                        {
                                            CopyProperties(tempDb95DeviceHis, db95DeviceHis);
                                        }
                                        Console.WriteLine(db95DeviceHis.Kr500Trigger);
                                        Console.WriteLine(db95DeviceHis.Kr16Time);
                                    }
                                }
                                catch (PlcException ex)
                                {
                                    errorTimes++;
                                    await Task.Delay(2000);

                                    Console.WriteLine($"读取时发生错误:{ex.Message}");
                                    Console.WriteLine($"读取时发生错误次数:{errorTimes}");
                                    s7Plc.Close();
                                    MyIsConnected = false;
                                    s7Plc = null;
                                }
                            }
                        }
                    },
                    cts.Token,
                    TaskCreationOptions.LongRunning,
                    TaskScheduler.Default
                );
            }
            catch (OperationCanceledException e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine("Service stopped");
            }
        }


        public void Pause()
        {
            Console.WriteLine("Pausing service...");
            autoReleaseSemaphore = false; // 禁止 ProcessAsync 自动 Release
        }

        public void Resume()
        {
            Console.WriteLine("Resuming service...");
            autoReleaseSemaphore = true; // 允许 ProcessAsync 自动 Release
            semaphore.Release(); // 手动触发一次 Release,唤醒阻塞的 WaitAsync
        }

        public void Stop()
        {
            Console.WriteLine("Stopping service...");
            cts.Cancel();
        }

        /// <summary>
        /// 反射复制属性值
        /// </summary>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public void CopyProperties(object source, object destination)
        {
            if (source == null || destination == null)
            {
                throw new ArgumentNullException("Either source or destination is null.");
            }

            Type sourceType = source.GetType();
            Type targetType = destination.GetType();

            foreach (
                PropertyInfo sourceProperty in sourceType.GetProperties(
                    BindingFlags.Public | BindingFlags.Instance
                )
            )
            {
                PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name);
                if (
                    targetProperty != null
                    && targetProperty.CanWrite
                    && sourceProperty.PropertyType == targetProperty.PropertyType
                )
                {
                    targetProperty.SetValue(destination, sourceProperty.GetValue(source));
                }
            }
        }
    }
}
csharp 复制代码
    public class Db95DeviceHis : INotifyPropertyChanged
    {
        public int Ret { get; set; }
        public float Kr16Time { get; set; }
        public float Kr500Time { get; set; }
        public float Dizuo1Time { get; set; }
        public float Dizuo2Time { get; set; }
        public float Dizuo3Time { get; set; }
        public float Kj1Time { get; set; }
        public float Kj2Time { get; set; }
        public float Kj3Time { get; set; }
        public float ZhouTime { get; set; }
        public float DamoTime { get; set; }

        public bool Kr16Trigger
        {
            get => kr16Trigger;
            set
            {
                if (kr16Trigger != value && value == true)
                {
                    NotifyPropertyChanged();
                }
                kr16Trigger = value;
            }
        }

        public bool Kr500Trigger
        {
            get => kr500Trigger;
            set
            {
                if (kr500Trigger != value && value == true)
                {
                    NotifyPropertyChanged();
                }
                kr500Trigger = value;
            }
        }


        private bool kr16Trigger;

        private bool kr500Trigger;

        public virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler? PropertyChanged;
    }
csharp 复制代码
    public interface IS7ConnService
    {
        void ConnPlc(string myIp, int dbNum, int startByte);
        void ConnPlc(string myIp);

        bool MyIsConnected
        {
            get;
        }

        Plc S7Plc { get; }
    }
相关推荐
yasuniko几秒前
C++线程库
开发语言·c++
@老蝴9 分钟前
C语言—指针2
c语言·开发语言
明月看潮生17 分钟前
青少年编程与数学 02-019 Rust 编程基础 01课题、环境准备
开发语言·青少年编程·rust·编程与数学
VBA633723 分钟前
VBA高级应用30例应用4:利用屏蔽事件来阻止自动运行事件
开发语言
Pop–33 分钟前
Vue3 el-tree:全选时只返回父节点,半选只返回勾选中的节点(省-市区-县-镇-乡-村-街道)
开发语言·javascript·vue.js
钢铁男儿41 分钟前
C# 方法(值参数和引用参数)
java·前端·c#
虚!!!看代码1 小时前
【JVM-GC调优】
java·开发语言·jvm
yuanyxh1 小时前
commonmark.js 源码阅读(一) - Block Parser
开发语言·前端·javascript
小白的代码日记1 小时前
java-反射精讲
java·开发语言
进取星辰1 小时前
22、城堡防御工事——React 19 错误边界与监控
开发语言·前端·javascript