.NET CancellationTokenSource and ManualResetEvent are used together

1. CancellationTokenSource is a class in C# used to cancel asynchronous operations. It provides a mechanism to cancel one or more asynchronous operations.

CancellationTokenSource contains the following main methods:

  1. Cancel(): This method cancels all pending operations and throws OperationCanceledException. If there are no pending operations when the Cancel() method is called, it has no effect.
  2. Cancel(boolean): This overloaded method allows you to cancel one or more specific pending operations. If Cancel(true) is called, all pending operations will be canceled and an OperationCanceledException exception will be thrown. If Cancel(false) is called, no operations will be canceled.
  3. IsCancellationRequested: This property returns a bool value indicating whether cancellation has been requested. Returns true if a cancellation operation has been requested; false otherwise.
  4. ThrowIfCancellationRequested(): This method checks whether a cancellation has been requested. If so, an OperationCanceledException exception is thrown.

CancellationTokenSource is typically used with CancellationToken. CancellationToken is a structure that provides a mechanism to request cancellation during an asynchronous operation. CancellationTokenSource can generate a CancellationToken, which can be passed to an asynchronous operation to request cancellation when the operation needs to be canceled.

The following is a simple example that demonstrates how to use CancellationTokenSource and CancellationToken to cancel an asynchronous operation:

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

In this example, we create a CancellationTokenSource object cts and an associated CancellationToken object token. We pass the CancellationToken object to the Task.Run method to check whether cancellation was requested in the asynchronous operation. If a cancellation operation is requested, an OperationCanceledException exception is thrown, thereby canceling the asynchronous operation. When we need to cancel the operation, we call the cts.Cancel() method to request the cancellation operation. 

 2. ManualResetEvent is a synchronization object used to control communication between threads in multi-thread programming. It allows one or more threads to wait for an event to occur and then continue execution after the event occurs.

When using ManualResetEvent, the following steps are typically required:

  1. Create a ManualResetEvent object. The initial state can be specified through the constructor. If the initial state is true, the thread can continue executing; otherwise, the thread will be blocked until the event is triggered.
  2. In the thread that needs to wait for an event to occur, call the WaitOne() method of ManualResetEvent. This will block the current thread until another thread calls the Set() method of ManualResetEvent to trigger the event.
  3. After the event occurs, another thread can call the Set() method of ManualResetEvent to trigger the event, which will allow the waiting thread to continue executing.
  4. If you need to manually reset the status of ManualResetEvent, you can call the Reset() method. In this way, any waiting threads will continue to be blocked until the Set() method is called again to trigger the event.

In short, ManualResetEvent can help synchronize between threads, allowing a thread to wait for another thread to complete a task before continuing.

3. General class examples

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; }
    }
}

Guess you like

Origin blog.csdn.net/weixin_50478033/article/details/133136410