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

news2025/7/19 12:39:26
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}");
            }
        }
    }
}

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中的应用:

using S7.Net;
using System.Reflection;

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("连接发生错误");
                                    Console.WriteLine(ex.GetType().Name);
                                    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 (IOException ex)
                                {
                                    errorTimes++;
                                    await Task.Delay(2000);
                                    Console.WriteLine("读取发生错误");
                                    Console.WriteLine(ex.GetType().Name);
                                    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));
                }
            }
        }
    }
}

    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;
    }
    public interface IS7ConnService
    {
        void ConnPlc(string myIp, int dbNum, int startByte);
        void ConnPlc(string myIp);

        bool MyIsConnected
        {
            get;
        }

        Plc? S7Plc { get; }
    }

program主程序

        static void Main(string[] args)
        {

            S7ConnServiceImpl serviceImpl = new(new Db95DeviceHis());

            serviceImpl.ConnPlc("192.168.2.10");


            Console.ReadLine();

            serviceImpl.Pause();

            Console.ReadLine();

            serviceImpl.Resume();

            Console.ReadLine();

            serviceImpl.Pause();

            Console.ReadLine();

            serviceImpl.Resume();

            Console.ReadLine();

            serviceImpl.Stop();

            Console.ReadLine();
            //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();
        }

结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2375027.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2025年AI工程师认证深度解析:AAIA认证体系全景指南与实战策略

一、IAAAI认证体系演进与价值定位 1.1 国际人工智能认证发展现状 全球人工智能认证市场呈现显著分化态势。据Gartner 2025Q1报告显示&#xff0c;北美市场以IEEE/ACM双认证体系为主导&#xff08;市占率38%&#xff09;&#xff0c;欧盟区推行AI Act合规认证&#xff08;强制…

统计服务器CPU、内存、磁盘、网络IO、队列、数据库占用空间等等信息

文章目录 一、背景二、说明三、页面四、代码 前端 MonitorServiceProcessPage.vueMonitorServiceProcessTable.vueMonitorServiceProcessTableButton.vueaddMonitorTask.vueproductOperation.vueshowMonitorTask.vueMonitorSystemLog.vueMonitorTask.vueMonitorTaskLog.vueReal…

-MAC桢-

MAC桢和IP的关系&#xff1a; 主机A想跨网络和B通信需要IP地址进行路由选择&#xff0c;但一个局域网&#xff0c;比如路由器进行路由选择之前&#xff0c;首先要将数据包发送给路由器B&#xff0c;也就是局域网通信也就是同一个网段的主机进行通信&#xff0c;所以必须通过mac…

安装:Kali2025+Docker

安装:Kali2025Docker Kali2025安装 直接官网下载WMware版本 https://www.kali.org/get-kali/#kali-virtual-machines 直接打开运行 初始用户密码 kali/kali sudo -i 命令切换到root 更换镜像 切换到其他可用的 Kali Linux 镜像源可能会解决问题,可以使用国内的镜像源&…

Linux云计算训练营笔记day04[Rocky Linux中的命令:mv、cp、grep(^$)、tar、重定向>和>>]

mv 移动(剪切) 源数据会消失 格式: mv 源文件 目标路径 touch /opt/a.txt 创建文件 mv /opt/a.txt /root 移动文件&#xff0c;没有改名 mkdir gongli 创建目录 mv gongli /opt/ 移动目录&#xff0c;没有改名 mv /opt/gongli tedu 移动目录&#xff0c;改名了 …

AbMole Olaparib:打破常规,用PARP抑制重塑肿瘤研究

在当今的生物医学研究领域&#xff0c;Olaparib&#xff08;AZD2281&#xff0c;AbMole&#xff0c;M1664&#xff09;作为一种重要的PARP&#xff08;聚腺苷二磷酸核糖聚合酶&#xff09;抑制剂&#xff0c;受到了广泛关注。Olaparib可干扰 DNA 单链断裂的修复&#xff0c;从而…

Windows重置网络,刷新缓存

同时按键盘上的【Windows】键和【S】键&#xff0c;弹出搜索框&#xff0c;输入 命令提示符 在“最佳匹配”下的【命令提示符】上右键&#xff0c;点击【以管理员身份运行】 1弹出一个窗口&#xff0c;在光标闪烁的位置&#xff0c;直接输入【netsh winsock reset】&#xff0…

OpenHarmony平台驱动开发(十),MMC

OpenHarmony平台驱动开发&#xff08;十&#xff09; MMC 概述 功能简介 MMC&#xff08;MultiMedia Card&#xff09;即多媒体卡&#xff0c;是一种用于固态非易失性存储的小体积大容量的快闪存储卡。 MMC后续泛指一个接口协定&#xff08;一种卡式&#xff09;&#xff0…

解决IDEA无法运行git的问题

之前git一直没有问题&#xff0c;今天打开就提示我安装git&#xff0c;自然用git去提交新项目也会遇到问题。 我出现问题的原因是&#xff1a;git路径缺失 文件->设置->git 发现git的路径为空&#xff0c;按照实际位置填写即可

HTTP 响应状态码总结

一、引言 HTTP 响应状态码是超文本传输协议&#xff08;HTTP&#xff09;中服务器对客户端&#xff08;通常是 Web 浏览器&#xff09;请求的响应指示。这些状态码是三位数字代码&#xff0c;用于告知客户端请求的结果&#xff0c;包括请求是否成功。响应被分为五个类别&#…

【Qt】Qt 构建系统详解:qmake 入门到项目实战

Qt 构建系统详解&#xff1a;qmake 入门到项目实战 本文将系统介绍 Qt 构建工具 qmake 的用法&#xff0c;并通过一个完整的项目结构示例&#xff0c;帮助你掌握 .pro 文件编写、子项目管理、模块依赖等核心技能。 &#x1f9ed; 一、什么是 qmake&#xff1f; qmake 是 Qt 提…

《Zabbix Proxy分布式监控实战:从安装到配置全解析》

注意&#xff1a;实验所需的zabbix服务器的搭建可参考博客 zabbix 的docker安装_docker安装zabbix-CSDN博客 1.1 实验介绍 1.1.1 实验目的 本实验旨在搭建一个基于Zabbix的监控系统&#xff0c;通过安装和配置Zabbix Proxy、MySQL数据库以及Zabbix Agent&#xff0c;实现分…

华为配置篇-RSTP/MSTP实验

MSTP 一、简介二、常用命令总结三、实验 一、简介 RSTP&#xff08;快速生成树协议&#xff09;​ RSTP&#xff08;Rapid Spanning Tree Protocol&#xff09;是 STP 的改进版本&#xff0c;基于 ​​IEEE 802.1w 标准​​&#xff0c;核心目标是解决传统 STP 收敛速度慢的问…

git如何将本地 dev 分支与远程 dev 分支同步

要让本地 dev 分支与远程 dev 分支完全同步&#xff08;丢弃本地多余的提交记录&#xff09;&#xff0c;可以按照以下步骤操作&#xff1a; 1. ​​获取远程最新状态​ git fetch origin dev # 拉取远程 dev 分支的最新提交&#xff0c;但不会修改本地代码 IDEA中点击fetc…

Unity基础学习(九)输入系统全解析:鼠标、键盘与轴控制

目录 一、Input类 1. 鼠标输入 2. 键盘输入 3. 默认轴输入 &#xff08;1&#xff09; 基础参数 &#xff08;2&#xff09;按键绑定参数 &#xff08;3&#xff09;输入响应参数 &#xff08;4&#xff09;输入类型与设备参数 &#xff08;5&#xff09;不同类型轴的参…

QT:获取软件界面窗口的尺寸大小2025.5.8

在Windows系统中&#xff0c;获取软件界面窗口的尺寸大小可以通过多种方法实现&#xff0c;以下是基于不同场景的详细解决方案&#xff1a; 方法1&#xff1a;使用Windows API获取窗口尺寸 适用于获取外部应用程序窗口的尺寸&#xff08;如记事本、计算器等&#xff09;。 步…

【ML-Agents】ML-Agents示例项目导入unity报错解决

最近在跑ML-Agents的示例代码&#xff0c;无奈往unity中导入项目后&#xff0c;就出现报错。本文简要描述了各个报错的解决方法。 文章目录 一、error CS0234: The type or namespace name InputSystem does not exist in the namespace UnityEngine (are you missing an assem…

Transformer Decoder-Only 参数量计算

Transformer 的 Decoder-Only 架构&#xff08;如 GPT 系列模型&#xff09;是当前大语言模型的主流架构&#xff0c;其参数量主要由以下几个部分组成&#xff1a; 嵌入层&#xff08;Embedding Layer&#xff09;自注意力层&#xff08;Self-Attention Layers&#xff09;前馈…

uni-app 中的条件编译与跨端兼容

uni-app 为了实现一套代码编译到多个平台&#xff08;包括小程序&#xff0c;App&#xff0c;H5 等&#xff09;&#xff0c;引入了条件编译机制。 通过条件编译&#xff0c;我们可以针对不同的平台编写特定的代码&#xff0c;从而实现跨端兼容。 一、条件编译的作用 平台差异…

Unity接入SDK之修改Unity启动页面

原理就是在Android Studio新建Activity继承UnityPlayerActivity&#xff0c;然后再Unity中修改启动页面。 一&#xff0c;Android Studio篇 首先新建一个项目&#xff0c; 新建完成之后基于新建的项目新建一个module&#xff0c;选择为Android Library类型 新建的Library再目…