久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

支持多線程的日志記錄類實(shí)現(xiàn)

 quasiceo 2013-03-04

支持多線程的日志記錄類實(shí)現(xiàn)

概述

主要設(shè)計(jì)思想是通過一個(gè)共享隊(duì)列,,多個(gè)輸入端能同時(shí)非阻塞式的向隊(duì)列中增加記錄信息,輸出端能自動及時(shí)的把隊(duì)列中的記錄信息輸出到控制臺或是保存到 文件及數(shù)據(jù)庫中,。多個(gè)輸入端互相隔離,,采用多線程實(shí)現(xiàn),但考慮到緩存日志信息的是一個(gè)共享隊(duì)列,,自然涉及到線程間的同步問題,。本文的實(shí)現(xiàn)模式是采用操作系 統(tǒng)中很經(jīng)典的生產(chǎn)者/消費(fèi)者模式。線程間的同步是通過事件信號,,同時(shí)對共享隊(duì)列的修改進(jìn)行加鎖保護(hù),,避免多個(gè)線程同時(shí)修改隊(duì)列。

日志記錄類實(shí)現(xiàn)

整個(gè)實(shí)現(xiàn)除了主要的日志記錄類,,還要定義同步事件類封裝用于線程間同步的事件對象,,定義日志信息類用于生成日志信息能存于共享隊(duì)列中。

1. 同步事件類 SyncEvents

該類的定義與使用參照《如何:對制造者線程和使用者線程進(jìn)行同步》

復(fù)制代碼
    public class SyncEvents
    {
        private EventWaitHandle _newItemEvent;      //添加新項(xiàng)
        private EventWaitHandle _exitThreadEvent;   //退出線程
        private WaitHandle[] _eventArray;

        public SyncEvents()
        {

            _newItemEvent = new AutoResetEvent(false);
            _exitThreadEvent = new ManualResetEvent(false);
            _eventArray = new WaitHandle[2];
            _eventArray[0] = _newItemEvent;
            _eventArray[1] = _exitThreadEvent;
        }

        public EventWaitHandle ExitThreadEvent
        {
            get { return _exitThreadEvent; }
        }
        public EventWaitHandle NewItemEvent
        {
            get { return _newItemEvent; }
        }
        public WaitHandle[] EventArray
        {
            get { return _eventArray; }
        }       
    }
復(fù)制代碼

對新記錄的添加使用 AutoResetEvent 類,,輸出端線程在響應(yīng)此事件后,,此事件能自動重置。將 ManualResetEvent 類用于通知線程退出,,該事件被設(shè)置后無論是向共享隊(duì)列中添加日志記錄的輸入端線程還是從共享隊(duì)列中取日志記錄的輸出端線程都能響應(yīng)此事件,,從而正常退出。

2. 日志信息類

共享隊(duì)列中存放的就是日志信息類的實(shí)例對象,,可以根據(jù)實(shí)際需要對此類中的屬性進(jìn)行增加與修改,,這并不影響下面將要介紹的日志記錄類正常使用,。

復(fù)制代碼
    public class LogInfo
    {
        private int _ID;
        public int ID
        {
            get { return _ID; }
            set { _ID = value; }
        }

        private string _CreateTime;
        public string CreateTime
        {
            get { return _CreateTime; }
            set { _CreateTime = value; }
        }

        private string _Content;
        public string Content
        {
            get { return _Content; }
            set { _Content = value; }
        }
    }
復(fù)制代碼

 

3. 日志記錄類

類中屬性與構(gòu)造函數(shù)

復(fù)制代碼
    public class Logger
    {
        private static Logger _logger;
        private static object _lock = new object();
        private static Thread _thread;
        //日志隊(duì)列
        private Queue<LogInfo> _queue;
        private SyncEvents _syncEvents;

        private Logger()
        {
            _queue = new Queue<LogInfo>();
            _syncEvents = new SyncEvents();
        }
        //獲取日志記錄類實(shí)例
        public static Logger GetLogger()
        {
            if (_logger == null)
            {
                //加鎖,防止多線程運(yùn)行時(shí),,重復(fù)創(chuàng)建,。
                lock (_lock)
                {
                    if (_logger == null)
                    {
                        _logger = new Logger();
                    }
                }
            }

            return _logger;
        }
    }
復(fù)制代碼

為了保證共享隊(duì)列唯一,此類實(shí)現(xiàn)采用了單例模式,,實(shí)現(xiàn)方式是通過定義一個(gè)靜態(tài)的 自身logger變量,,私有化默認(rèn)的構(gòu)造函數(shù),提供一個(gè)得到Logger實(shí)例的GetLogger方法,。這樣不能通過new直接創(chuàng)建Logger實(shí)例,,只 能通過GetLogger方法獲得,在該方法中就可以通過判斷是否已創(chuàng)建了Logger實(shí)例,,如果已創(chuàng)建則返回已有的,,從而保證Logger實(shí)例的唯一。

 

添加日志方法

復(fù)制代碼
        private void AddLog(Object obj)
        {
            LogInfo log = obj as LogInfo;
            if (!_syncEvents.ExitThreadEvent.WaitOne(0, false))
            {
                lock (((ICollection)_queue).SyncRoot)
                {
                    _queue.Enqueue(log);
                    _syncEvents.NewItemEvent.Set();
                    Console.WriteLine("Input thread: add {0} items", log.ID);
                }
            }
            
        }
        /// <summary>
        /// 添加日志
        /// </summary>
        /// <param name="log"></param>
        public void Add(LogInfo log)
        {
            Thread t = new Thread(AddLog);
            t.Start(log);
        }
復(fù)制代碼

首先檢查“退出線程”事件,,因?yàn)?WaitOne 使用的第一個(gè)參數(shù)為零,,該方法會立即返回,所以檢查該事件的狀態(tài)不會阻止當(dāng)前線程,。接著往共享隊(duì)列中添加日志記錄并設(shè)置“添加新項(xiàng)”事件,,此事件設(shè)置后會 讓因共享隊(duì)列為空而一直在等待的輸出線程繼續(xù)運(yùn)行,處理共享隊(duì)列中的新日志記錄,。 日志添加通過調(diào)用Add方法,,啟動一個(gè)新線程運(yùn)行AddLog方法向共享隊(duì)列中添加新日志。


日志輸出方法

復(fù)制代碼
        /// <summary>
        /// 日志保存
        /// </summary>
        private void Save()
        {
            int flag = 0;
            while (flag >=0 )
            {
                if (_queue.Count == 0)
                {
                   flag = WaitHandle.WaitAny(_syncEvents.EventArray);
                   if (flag == 1)
                   {
                       flag = -1;
                   } 
                }
                lock (((ICollection)_queue).SyncRoot)
                {
                    if (_queue.Count > 0)
                    {
                        LogInfo log = _queue.Dequeue();
                        Console.WriteLine("Output Thread: process {0} items", log.ID);
                    }

                }
            }
            
        }
        public void Run()
        {
            _thread = new Thread(Save);
            _thread.Start();
        }
復(fù)制代碼

輸出線程主要運(yùn)行的就是日志保存方法,,通過while循環(huán)逐個(gè)處理共享隊(duì)列中的 日志記錄。如果隊(duì)列為空,,則線程暫停進(jìn)入等待狀態(tài),,等待“添加新項(xiàng)”事件或“退出線程”事件,兩個(gè)事件只要有一個(gè)被設(shè)置則線程繼續(xù)運(yùn)行,,如果是“退出線 程”事件,,則設(shè)置flag為-1,退出循環(huán)線程結(jié)束,,因?yàn)橹挥性陉?duì)列為空時(shí)才等待“退出線程”事件,,這樣保證線程退出前隊(duì)列中的所有的日志記錄都被處理。 在程序開始處就運(yùn)行Run方法,,會啟動一個(gè)新線程運(yùn)行Save方法,,這樣只要一添加日志就能自動的被處理。


線程結(jié)束方法

 

        public void Stop()
        {
            _syncEvents.ExitThreadEvent.Set();
        }

通過設(shè)置“退出線程”事件,,讓正在運(yùn)行的輸入線程和輸出線程都自動結(jié)束運(yùn)行,。

4. 使用示例

復(fù)制代碼
    class Program
    {
        static void Main(string[] args)
        {
            Logger logger = Logger.GetLogger();
            logger.Run();

            for (int i = 0; i < 100; i++)
            {

                LogInfo log = new LogInfo();
                log.ID = i;
                logger.Add(log);
                if (i == 50)
                {
                    logger.Stop();
                }
            }


            Console.ReadLine();
        }
    }
復(fù)制代碼

 這只是個(gè)人學(xué)習(xí)多線程相關(guān)知識而簡單實(shí)現(xiàn)的日志類,,功能簡單也未做任何優(yōu)化。如果需要在實(shí)際項(xiàng)目中使用日志記錄功能,,推薦開源的Nlog

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多