ManualResetEvent
ManualResetEvent 类似于AutoResetEvent,不过要手动设置Reset;并且ManualResetEvent可以控制多个线程协调。
ManualResetEventSlim 是轻型级的类,可以替代ManualResetEvent 使用。
Wait()内部轮询检测。判断IsSet属性,如果为false,线程会挂起;如果为true,线程不会挂起,会继续执行。
Reset()重置信号,IsSet=false。
Set() 设置信号,IsSet=true。
高并发写日志
ManualResetEventSlim实现日志,通知线程在队列中有新的内容,当队列中写完日志后,重置信号,等待下次日志信息。
using log4net;
using log4net.Config;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
/* 优点:适用高并发场景,高性能写日志
   缺点:程序崩溃或电脑断电,队列中的日志可能未写完而丢失
 */
public class LogHelper
{
    // 延迟加载
    private static readonly Lazy<LogHelper> _lazy = new Lazy<LogHelper>(() => new LogHelper());
    /// <summary>
    /// 单例
    /// </summary>
    public static LogHelper Instance() => _lazy.Value;
    private LogHelper()
    {
        var configFile = "log4net.config";
        var fi = new FileInfo(configFile);
        if (!fi.Exists)
        {
            throw new Exception("log4net.config is NULL!");
        }
        XmlConfigurator.Configure(fi);
        _log = LogManager.GetLogger(typeof(LogHelper));
        _queue = new ConcurrentQueue<LogMessage>();
        // 创建无信号状态
        _mre = new ManualResetEventSlim(false);
    }
    /// <summary>
    /// 日志
    /// </summary>
    private readonly ILog _log;
    /// <summary>
    /// 信号
    /// </summary>
    private readonly ManualResetEventSlim _mre;
    /// <summary>
    /// 队列
    /// </summary>
    private readonly ConcurrentQueue<LogMessage> _queue;
    // 线程记录日志,只在程序初始化时调用一次
    public void Register()
    {
        Task.Run(WriteLogAsync);
    }
    private async Task WriteLogAsync()
    {
        while (true)
        {
            // 等待。收到被设置信号true,不再阻塞,继续执行后续代码
            _mre.Wait();
            // 从队列写入磁盘
            LogMessage msg;
            while (_queue.Count > 0 && _queue.TryDequeue(out msg))
            {
                switch (msg.Level)
                {
                    case LogLevel.Debug:
                        _log.Debug(msg.Message, msg.Exception);
                        break;
                    case LogLevel.Info:
                        _log.Info(msg.Message, msg.Exception);
                        break;
                    case LogLevel.Warn:
                        _log.Warn(msg.Message, msg.Exception);
                        break;
                    case LogLevel.Error:
                        _log.Error(msg.Message, msg.Exception);
                        break;
                    case LogLevel.Fatal:
                        _log.Fatal(msg.Message, msg.Exception);
                        break;
                    default:
                        break;
                }
            }
            // 必须手动重置信号false
            _mre.Reset();
            await Task.Delay(1);
        }
    }
    public void EnqueueMessage(string message, LogLevel level, Exception ex = null)
    {
        if ((level == LogLevel.Debug && _log.IsDebugEnabled) ||
            (level == LogLevel.Info && _log.IsInfoEnabled) ||
            (level == LogLevel.Warn && _log.IsWarnEnabled) ||
            (level == LogLevel.Error && _log.IsErrorEnabled) ||
            (level == LogLevel.Fatal && _log.IsFatalEnabled))
        {
            _queue.Enqueue(new LogMessage
            {
                Message = message,
                Level = level,
                Exception = ex,
            });
            // 设置信号true。通知线程
            _mre.Set();
        }
    }
    public static void Debug(string msg, Exception ex = null)
    {
        Instance().EnqueueMessage(msg, LogLevel.Debug, ex);
    }
    public static void Info(string msg, Exception ex = null)
    {
        Instance().EnqueueMessage(msg, LogLevel.Info, ex);
    }
    public static void Warn(string msg, Exception ex = null)
    {
        Instance().EnqueueMessage(msg, LogLevel.Warn, ex);
    }
    public static void Error(string msg, Exception ex = null)
    {
        Instance().EnqueueMessage(msg, LogLevel.Error, ex);
    }
    public static void Fatal(string msg, Exception ex = null)
    {
        Instance().EnqueueMessage(msg, LogLevel.Fatal, ex);
    }
}
/// <summary>
/// 日志内容
/// </summary>
public class LogMessage
{
    public string Message { get; set; }
    public LogLevel Level { get; set; }
    public Exception Exception { get; set; }
}
/// <summary>
/// 日志等级
/// </summary>
public enum LogLevel
{
    Debug,
    Info,
    Warn,
    Error,
    Fatal,
}
多线程暂停/继续
private static CancellationTokenSource _cts;
private readonly object _objLock = new object();
private readonly ManualResetEventSlim _manualResetEvent = new ManualResetEventSlim(false);
private int _value;
private readonly List<Task> _tasks = new List<Task>();
// 多线程启动
private async void btnStartup_Click(object sender, EventArgs e)
{
    Cancel();
    _cts = new CancellationTokenSource();
    _manualResetEvent.Set();
    _value = 0;
    for (int i = 0; i < 10; i++)
    {
        var t = WSCommFunc.LongCustomThread(TaskMethod, _cts);
        _tasks.Add(t);
    }
    await Task.WhenAll(_tasks.ToArray());
    Console.WriteLine("OKKK");
}
// 暂停
private void btnSuspend_Click(object sender, EventArgs e)
{
    _manualResetEvent.Reset();
    Console.WriteLine("Suspend.....");
}
// 继续
private void btnGetWaferID_Click(object sender, EventArgs e)
{
    _manualResetEvent.Set();
    Console.WriteLine("Resume.....");
}
// 取消
private void Cancel()
{
    _tasks.Clear();
    _manualResetEvent.Reset();
    GlobalCommFunc.Disponse(_cts);
}
private void TaskMethod()
{
    try
    {
        using (new ThreadPriorityScope(ThreadPriority.AboveNormal)) // 设置优先级
        {
            Console.WriteLine(string.Format("Name={0}, Id={1} Priority:{2}", Thread.CurrentThread.Name, Environment.CurrentManagedThreadId, Thread.CurrentThread.Priority));
            while (!_cts.IsCancellationRequested)
            {
                _manualResetEvent.Wait();
                lock (_objLock)
                {
                    _value++;
                    if (_value >= 200)
                    {
                        _value = 0;
                    }
                }
                this.OnUIThread(() => { txtDisplay.Text = _value.ToString(); });
                Thread.Sleep(1000);
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
    finally
    {
        Console.WriteLine(string.Format("Name={0}, Id={1} Priority:{2}.......END", Thread.CurrentThread.Name, Environment.CurrentManagedThreadId, Thread.CurrentThread.Priority));
    }
}
public class ThreadPriorityScope : IDisposable
{
    private readonly ThreadPriority _priority;
    public ThreadPriorityScope(ThreadPriority priority)
    {
        _priority = Thread.CurrentThread.Priority;
        Thread.CurrentThread.Priority = priority;
    }
    public void Dispose()
    {
        Thread.CurrentThread.Priority = _priority;
    }
}
参考链接:同步基元概述

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号