异常问题记录:
本想自己手动实现一个日志记录功能。使用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; }
}
}
}
View Code
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>
/// 日志操作辅助类
/// [email protected]
/// 创建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();
}
}
}
- 学习本是一个不断抄袭、模仿、练习、创新的过程。
- 虽然,园中已有本人无法超越的同主题博文,为什么还是要写。
- 对于自己,博文只是总结。在总结的过程发现问题,解决问题。
- 对于他人,在此过程如果还能附带帮助他人,那就再好不过了。
- 由于博主能力有限,文中可能存在描述不正确,欢迎指正、补充!
- 感谢您的阅读。如果文章对您有用,那么请轻轻点个赞,以资鼓励。
- 工控物联Q群:995475200