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号