.NET的CancellationTokenSource和ManualResetEvent结合使用

这篇具有很好参考价值的文章主要介绍了.NET的CancellationTokenSource和ManualResetEvent结合使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、CancellationTokenSource 是 C# 中的一个类,用于取消异步操作。它提供了一种机制,可以取消一个或多个异步操作。

CancellationTokenSource 包含以下主要方法:

  1. Cancel(): 该方法会取消所有挂起的操作,并引发 OperationCanceledException 异常。如果在调用 Cancel() 方法时没有挂起的操作,则没有任何效果。
  2. Cancel(boolean): 这个重载方法允许您取消一个或多个特定的挂起操作。如果Cancel(true)被调用,那么所有挂起的操作都将被取消,并引发 OperationCanceledException 异常。如果Cancel(false)被调用,那么不会有任何操作被取消。
  3. IsCancellationRequested: 这个属性会返回一个 bool 值,表明是否已经请求取消操作。如果已经请求取消操作,则返回 true;否则返回 false。
  4. ThrowIfCancellationRequested(): 这个方法会检查是否已经请求取消操作。如果是这样,那么会引发 OperationCanceledException 异常。

CancellationTokenSource 通常与 CancellationToken 一起使用。CancellationToken 是一个结构,它提供了一种机制,可以在异步操作中请求取消操作。CancellationTokenSource 可以生成一个 CancellationToken,这个 token 可以传递给异步操作,以便在需要取消操作时请求取消。

以下是一个简单的示例,演示如何使用 CancellationTokenSource 和 CancellationToken 来取消一个异步操作:

CancellationTokenSource cts = new CancellationTokenSource();  
CancellationToken token = cts.Token;  
  
Task.Run(() =>   
{  
    while (true)  
    {  
        token.ThrowIfCancellationRequested();  
        // 异步操作代码...  
    }  
}, cts.Token);  
  
// 在需要取消操作时调用以下方法:  
cts.Cancel();

在这个示例中,我们创建了一个 CancellationTokenSource 对象 cts 和一个与之关联的 CancellationToken 对象 token。我们将 CancellationToken 对象传递给 Task.Run 方法,以便在异步操作中检查是否请求了取消操作。如果取消操作被请求,则会引发 OperationCanceledException 异常,从而取消异步操作。在需要取消操作时,我们调用 cts.Cancel() 方法来请求取消操作。 

 二、ManualResetEvent是一种同步对象,用于在多线程编程中控制线程之间的通信。它允许一个或多个线程等待某个事件发生,然后在事件发生后继续执行。

使用ManualResetEvent时,通常需要以下步骤:

  1. 创建一个ManualResetEvent对象。可以通过构造函数来指定初始状态,如果初始状态为真,则线程可以继续执行;否则,线程将被阻塞直到事件被触发。
  2. 在需要等待某个事件发生的线程中,调用ManualResetEvent的WaitOne()方法。这将会阻塞当前线程,直到另一个线程调用ManualResetEvent的Set()方法触发事件。
  3. 在事件发生后,另一个线程可以调用ManualResetEvent的Set()方法来触发事件,这将使得等待的线程可以继续执行。
  4. 如果需要手动重置ManualResetEvent的状态,可以调用Reset()方法。这样,任何等待的线程将会继续被阻塞,直到再次调用Set()方法触发事件。

总之,ManualResetEvent可以帮助线程间进行同步,使得线程可以等待另一个线程完成某个任务后才继续执行。

3、通用类示例文章来源地址https://www.toymoban.com/news/detail-732188.html

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;

namespace Common
{
    /// <summary>
    /// 线程通用类
    /// </summary>
    public class TaskCommand
    {
        //用于取消异步操作
        CancellationTokenSource tokenSource = new CancellationTokenSource();
        //用于在多线程编程中控制线程之间的通信
        ManualResetEvent resetEvent = new ManualResetEvent(true);
        Thread thread = null;

        /// <summary>
        /// 队列对象
        /// </summary>
        private Queue<MeterAsyncQueue> AsyncQueues { get; set; }

        /// <summary>
        /// 并发任务数
        /// </summary>
        private int ParallelTaskCount { get; set; }

        /// <summary>
        /// 并行任务集合
        /// </summary>
        private List<Task> ParallelTasks { get; set; }

        /// <summary>
        /// 是否首次执行任务
        /// </summary>
        private bool IsInitTask { get; set; }

        /// <summary>
        /// 锁
        /// </summary>
        private readonly object _objLock = new object();

        /// <summary>
        /// 获取队列锁
        /// </summary>
        private readonly object _queueLock = new object();

        /// <summary>
        /// 开始任务
        /// </summary>
        public void StartData()
        {
            tokenSource = new CancellationTokenSource();
            resetEvent = new ManualResetEvent(true);

            List<int> Ids = new List<int>();
            for (int i = 0; i < 10000; i++)
            {
                Ids.Add(i);
            }
            thread = new Thread(new ThreadStart(() => StartTask(Ids)));
            thread.Start();
        }

        /// <summary>
        /// 暂停任务
        /// </summary>
        public void OutData()
        {
            //task暂停
            resetEvent.Reset();
        }

        /// <summary>
        /// 继续任务
        /// </summary>
        public void ContinueData()
        {
            //task继续
            resetEvent.Set();
        }

        /// <summary>
        /// 取消任务
        /// </summary>
        public void Cancel()
        {
            //释放对象
            resetEvent.Dispose();
            foreach (var CurrentTask in ParallelTasks)
            {
                if (CurrentTask != null)
                {
                    if (CurrentTask.Status == TaskStatus.Running) { }
                    {
                        //终止task线程
                        tokenSource.Cancel();
                    }
                }
            }
            thread.Abort();
        }

        /// <summary>
        /// 执行数据
        /// </summary>
        /// <param name="Index"></param>
        public void Execute(int Index)
        {
            //阻止当前线程
            resetEvent.WaitOne();

            Console.WriteLine("当前第" + Index + "个线程");

            Thread.Sleep(1000);
        }

        //控制线程并行数量
        public void StartTask(List<int> Ids)
        {
            IsInitTask = true;
            ParallelTasks = new List<Task>();
            AsyncQueues = new Queue<MeterAsyncQueue>();
            //获取并发数
            ParallelTaskCount = 5;
            //初始化异步队列
            InitAsyncQueue(Ids);
            //开始执行队列任务
            HandlingTask();

            Task.WaitAll(new Task[] { Task.WhenAll(ParallelTasks.ToArray()) });
        }

        /// <summary>
        /// 初始化异步队列
        /// </summary>
        private void InitAsyncQueue(List<int> Ids)
        {
            foreach (var item in Ids)
            {
                MeterInfo info = new MeterInfo();
                info.Id = item;
                AsyncQueues.Enqueue(new MeterAsyncQueue()
                {
                    MeterInfoTask = info
                });
            }
        }

        /// <summary>
        /// 开始执行队列任务
        /// </summary>
        private void HandlingTask()
        {
            lock (_objLock)
            {
                if (AsyncQueues.Count <= 0)
                {
                    return;
                }

                var loopCount = GetAvailableTaskCount();
                //并发处理队列
                for (int i = 0; i < loopCount; i++)
                {
                    HandlingQueue();
                }
                IsInitTask = false;
            }
        }

        /// <summary>
        /// 处理队列
        /// </summary>
        private void HandlingQueue()
        {
            CancellationToken token = tokenSource.Token;
            lock (_queueLock)
            {
                if (AsyncQueues.Count > 0)
                {
                    var asyncQueue = AsyncQueues.Dequeue();

                    if (asyncQueue == null) return;
                    var task = Task.Factory.StartNew(() =>
                    {
                        if (token.IsCancellationRequested)
                        {
                            return;
                        }
                        //阻止当前线程
                        resetEvent.WaitOne();
                        //执行任务
                        Execute(asyncQueue.MeterInfoTask.Id);

                    }, token).ContinueWith(t =>
                    {
                        HandlingTask();
                    }, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.ExecuteSynchronously);
                    ParallelTasks.Add(task);
                }
            }
        }

        /// <summary>
        /// 获取当前有效并行的任务数
        /// </summary>
        /// <returns></returns>
        [MethodImpl(MethodImplOptions.Synchronized)]
        private int GetAvailableTaskCount()
        {
            if (IsInitTask)
                return ParallelTaskCount;
            return 1;
        }
    }

    // <summary>
    /// 并发对象
    /// </summary>
    public class MeterAsyncQueue
    {
        public MeterAsyncQueue()
        {
            MeterInfoTask = new MeterInfo();
        }
 
        public MeterInfo MeterInfoTask { get; set; }
    }

    public class MeterInfo
    {
        public MeterInfo()
        {
 
        }
        public int Id { get; set; }
    }
}

到了这里,关于.NET的CancellationTokenSource和ManualResetEvent结合使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [C#]OpenCvSharp结合yolov8-face实现L2CS-Net眼睛注视方向估计或者人脸朝向估计

    github地址:https://github.com/Ahmednull/L2CS-Net L2CS-Net介绍: 眼睛注视(eye gaze) 是在各种应用中使用的基本线索之一。 它表示用户在人机交互和开放对话系统中的参与程度。此外,它还被用于增强现实,用于预测用户的注意力,从而提高设备的感知能力,降低功耗。 因此,研究人

    2024年01月16日
    浏览(40)
  • .Net6下使用Ado.Net

    Ado.Net,是微软提供的在.Net平台下操作数据库(本文实例记录MySQL、SQLSever数据的基本操作)、XML文件和应用程序数据的一个工具。是应用程序和数据库之间的数据桥梁。它拥有一组丰富的类、方法和接口,有效地处理数据库中的数据。(上层的ORM框架《EFCore、Dapper等》都是对它

    2024年02月05日
    浏览(52)
  • C# .NET ADO.NET介绍和如何使用

    .NET Framework 4.7.2 Visual Studio 2022 Sql server 2008 新建项目 我们看一下visual studio 里面ADO.NET文件 ADO.NET是实体数据模型,是ORM对象文件。ORM,即Object-Relational Mapping(对象关系映射)。 ORM实际上是对业务的简化。就想面向过程到面向对象的转变一样。 面向过程和面向对象 面向过程:程序

    2024年02月09日
    浏览(64)
  • 【C#/.NET】使用ASP.NET Core对象池

    Microsoft.Extensions.ObjectPool   减少初始化/资源分配,提高性能。这一条与线程池同理,有些对象的初始化或资源分配耗时长,复用这些对象减少初始化和资源分配。比如:我有一个执行耗时约500毫秒,内存空间 2KB的任务为此创建一个新线程异步执行,而创建线程耗时1秒,内存空

    2024年02月06日
    浏览(67)
  • C# | 使用AutoResetEvent和ManualResetEvent进行线程同步和通信

    使用AutoResetEvent和ManualResetEvent进行线程同步和通信 文章目录 使用AutoResetEvent和ManualResetEvent进行线程同步和通信 介绍 AutoResetEvent ManualResetEvent 异同点 使用场景和代码示例 AutoResetEvent 使用示例 ManualResetEvent 使用示例 阻塞多个线程并同时激活 介绍 在多线程编程中,AutoResetEven

    2024年02月20日
    浏览(40)
  • 使用.NET Jieba.NET 的 PosSegmenter 实现中文分词匹配

    ​ 目录 引言 1. 什么是中文分词 2. Jieba.NET简介 3. PosSegmenter介绍 4. 实现中文分词匹配 4.1 安装Jieba.NET库 4.2 创建PosSegmenter实例 4.3 分词和词性标注 4.4 中文分词匹配 5. 总结           在自然语言处理领域,中文分词是一个重要且基础的任务。中文文本通常没有像英文那样的

    2024年02月11日
    浏览(76)
  • .NET6入门:2.使用模板创建.NET Core Web

                    在目前B/S盛行的时代,本文将通过创建一个.NET Core Web模板的方式来带领大家进入.NET6开发的大门。         1.1 打开Visual Studio(不同版本VS可能创建新项目所在位置不同),单击创建新项目。         1.2 选择C#语言和Web平台,在下面的项目中选中ASP.NET Core Web应

    2024年02月12日
    浏览(48)
  • Asp.Net 6中使用Log4Net

    log4net Microsoft.Extensions.Logging.Log4Net.AspNetCore log4net配置参数此处不多赘述,只针对日志的输出格式参数conversionPattern配置做简要说明。 新建一个ITestLog4Net接口文件,并为其定义一个Log方法 并且新建一个TestLog4Net的自定义类,继承于ITestLog4Net,并实现该Log方法。 在Program中注入我

    2024年02月15日
    浏览(44)
  • Asp.Net 使用Log4Net (基础版)

    创建ASP.NET Web Forms项目 在Visual Studio中创建一个新的ASP.NET Web Forms项目。命名为\\\"Log4NetDemo\\\"。 打开NuGet包管理器控制台,并运行以下命令来安装Log4Net: 在Web.config文件中添加Log4Net的配置。将以下内容粘贴到Web.config文件中。 在Global.asax文件中,我们需要初始化Log4Net。在 Applicatio

    2024年02月15日
    浏览(46)
  • Asp.Net MVC 使用Log4Net

    在 ASP.NET MVC 中使用 Log4net 需要进行一些配置和代码集成。下面是在 ASP.NET MVC 中使用 Log4net 的步骤: 打开 NuGet 包管理器控制台,并运行以下命令来安装 Log4net: 在你的 ASP.NET MVC 项目中,创建一个名为 log4net.config 的文件(或者其他名称,只要后缀是 .config 即可),用于配置

    2024年02月15日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包