异常问题记录:
本想自己手动实现一个日志记录功能。使用Queue队列集合来实现多线程的日志记录。
测试 一个线程写入数据Enqueue和一个线程读取数据Dequeue ,直接用的无休眠死循环。
终于抛出异常:源数组长度不足。请检查 srcIndex 和长度以及数组的下限。
于是百度之。百度结果 说是多线程写入数据 需要锁定操作lock。
尝试后无效果 依然报异常。
最后解决办法 是 在 Queue 读和 都加上锁定。测试N多线程同时写入和读错都能正常。
LogModel类
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web; using System.Web.UI; namespace Common.Helper.LogHelper { /// <summary> /// 日志模型 /// </summary> public class LogModel { /// <summary> /// 日志要存的路径 默认路径:网站根目录 + Log 文件夹 /// </summary> public string logFilePath = HttpContext.Current.Server.MapPath("~/") + @"\Log\"; private string _logFileName; /// <summary> /// 日志文件名字 /// </summary> public string logFileName { get { return _logFileName + "_" + DateTime.Now.ToString("yyyyMMdd"); } set { _logFileName = value; } } private string _logMessg; /// <summary> /// 日志内容 /// </summary> public string logMessg { get { return "====begin====================" + DateTime.Now.ToString() + "====Queue.Count:" + LogHelper.LogQueue.Count + "====================\r\n\r\n" + _logMessg + "\r\n\r\n====end====================" + DateTime.Now.ToString() + "====Queue.Count:" + LogHelper.LogQueue.Count + "====================" + "\r\n\r\n\r\n"; } set { _logMessg = value; } } } }
LogHelper类
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Common.Helper.LogHelper { /// <summary> /// 日志操作辅助类 /// zhaopeiym@163.com /// 创建20150104 修改20150104 /// </summary> public class LogHelper { /// <summary> /// 消息队列 /// </summary> private static Queue<LogModel> logQueue = new Queue<LogModel>(); /// <summary> /// 消息队列 对外只读 /// </summary> public static Queue<LogModel> LogQueue { get { return LogHelper.logQueue; } } /// <summary> /// 标志锁 /// </summary> static string myLock = "true"; /// <summary> /// 写入日志文件 /// </summary> /// <param name="logmede"></param> public static void logWrite(LogModel logmede) { // 这里需要锁上 不然会出现:源数组长度不足。请检查 srcIndex 和长度以及数组的下限。异常 //网上有资料说 http://blog.csdn.net/greatbody/article/details/26135057 不能多线程同时写入队列 //其实 不仅仅 不能同时写入队列 也不能同时读和写如队列 所以 在Dequeue 取的时候也要锁定一个对象 lock (myLock) logQueue.Enqueue(logmede); logStartWrite(); } /// <summary> /// 部分日志文件大小 /// </summary> public static int SectionlogFileSize = 1024 * 1024 * 1; // 1024Byte * 1024KB * 1MB /// <summary> /// 变动文件大小 /// </summary> public static int fileSize = 1024 * 1024 * 4; /// <summary> /// 文件编码格式 /// </summary> public static Encoding encoding = Encoding.Default; /// <summary> /// 是否开始自动记录日志 /// </summary> private static bool isStart = false; /// <summary> /// 开始把队列消息写入文件 /// </summary> private static void logStartWrite() { if (isStart) return; isStart = true; Thread t = new Thread(delegate() { while (true) { if (LogHelper.logQueue.Count >= 1) { LogModel m = null; lock (myLock) m = LogHelper.logQueue.Dequeue(); if (m == null) continue; if (!Directory.Exists(m.logFilePath)) Directory.CreateDirectory(m.logFilePath); int i = 0; //部分 日志 文件路径 string SectionfileFullName = m.logFilePath + m.logFileName + "_" + i.ToString("000") + ".txt"; //最新的写了内容的 部分 日志文件路径 string TopSectionfileFullName = SectionfileFullName; // 需要实时更新的 最新日志文件 路径 string LogfileFullNqme = m.logFilePath + m.logFileName + ".txt"; FileInfo file = new FileInfo(SectionfileFullName); while (file.Exists && file.Length >= LogHelper.SectionlogFileSize) { TopSectionfileFullName = SectionfileFullName; i++; SectionfileFullName = m.logFilePath + m.logFileName + "_" + i.ToString("000") + ".txt"; file = new FileInfo(SectionfileFullName); } try { if (!file.Exists)//如果不存在 这个文件 就说明需要 创建新的部分日志文件了 { //因为SectionfileFullName路径的文件不存在 所以创建 File.WriteAllText(SectionfileFullName, m.logMessg, encoding); FileInfo Logfile = new FileInfo(LogfileFullNqme); if (Logfile.Exists && Logfile.Length >= LogHelper.fileSize) //先清空 然后加上 上一个部分文件的内容 File.WriteAllText(LogfileFullNqme, File.ReadAllText(TopSectionfileFullName, encoding), encoding);//如果存在则覆盖 } else File.AppendAllText(SectionfileFullName, m.logMessg, encoding);//累加 //追加这次内容 到动态更新的日志文件 File.AppendAllText(LogfileFullNqme, m.logMessg, encoding); } catch (Exception ex) { throw ex; } } else { isStart = false;//标记下次可执行 break;//跳出循环 } } }); t.Start(); } } }