異常問題記錄:
本想自己手動實作一個日志記錄功能。使用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