Queue插入的时候报错:源数组长度不足。请检查 srcIndex 和长度以及数组的下限。

异常问题记录:

本想自己手动实现一个日志记录功能。使用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>
    /// 日志操作辅助类
    /// 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();
        }
    }
}
View Code