C# 中的 AutoResetEvent 关键字
在工作的任务中,需要对客户端和服务端 通信包进行落地。把这个做成通用的模块,在高并发和多线程下,也能够工作。
在查阅了大众化日志方案后,决定采用:写日志和写文件分离的方式进行。大概内容图:
需要记录是通信包,将需要记录的通信包推送到队列,再由一个专门的线程去读取队列,将出队列的数据写到文件中。这样将每次直接IO瓶颈,转化成存储队列的大小,瓶颈变成了内存的大小。上代码:
1 2 3 4 5 6 7 8 9 10 11
| private static readonly Thread LogThread;
private static readonly ConcurrentQueue<Message> LogQueue;
private static readonly object SyncRoot;
private static readonly AutoResetEvent AutoReset = null;
|
1 2 3 4 5 6 7 8 9
| static Utils() { AutoReset = new AutoResetEvent(false); SyncRoot = new object(); LogThread = new Thread(WriteLog); LogQueue = new ConcurrentQueue<Message>(); LogThread.Start(); }
|
1 2 3 4 5 6 7 8 9 10 11
| public static void Log(List<Message> msg) { foreach (var item in msg) { LogQueue.Enqueue(item); } AutoReset.Set(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| private static void WriteLog() { var list = new List<Message>(); while (true) { if (LogQueue.Count() > 0) { IT2ESBMessage _msg; LogQueue.TryDequeue(out _msg); if (_msg!=null) { list.Add(_msg); } } else { if (list.Count>0) { lock (SyncRoot) { foreach (var item in list) { ProcessWriteLog(item); } } ist.Clear(); } AutoReset.WaitOne(); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| private static void ProcessWriteLog(Message msg) { try { FileStream fs; fs = new FileStream(_fileName, FileMode.Append, FileAccess.Write); } catch (Exception ex) { Debug.WriteLine(string.Format("写入日志失败,原因:{0}", ex.Message)); } }
|
AutoResetEvent 关键字
有点类似于计算机中的信号量,回顾《操作系统》中的信号量吧,什么银行家算法,什么信号量已经忘得一干二净了。
信号量 用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作。
互斥锁 是用在多线程多任务互斥的,一个线程占用了某一个资源,那么别的线程就无法访问,直到这个线程unlock,其他的线程才开始可以利用这个资源