csharp 用于CLI的多线程记录器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了csharp 用于CLI的多线程记录器相关的知识,希望对你有一定的参考价值。

namespace Sample
{
    using System;
    using System.Collections.Concurrent;
    using System.IO;
    using System.Threading;
    using System.Threading.Tasks;

    /// <summary>
    /// This class allows multiple threads to write without blocking and serializes the writes to a single
    /// consumer thread.
    /// </summary>
    public class SynchronizedIO<T> : IDisposable
    {
        Action<T> writer;
        ConcurrentQueue<T> queue;
        Task task;
        bool quit;
        AutoResetEvent signal;

        public SynchronizedIO(Action<T> writer)
        {
            this.writer = writer;
            this.queue = new ConcurrentQueue<T>();
            this.signal = new AutoResetEvent(false);
            this.task = new Task(MonitorQueue);
            this.task.Start();
        }

        public void Enqueue(T data)
        {
            // add data to queue
            queue.Enqueue(data);

            // signal the monitor thread that there is work to be done
            signal.Set();
        }

        /// <summary>
        /// Finish any pending writes and then close the streams.
        /// </summary>
        public void Dispose()
        {
            // Signal the monitor thread that there is work to be done and that
            // it should exit.
            quit = true;
            signal.Set();

            // wait until it finishes
            task.Wait();
        }

        /// <summary>
        /// Synchronously commit any queued data.
        /// </summary>
        public void Flush()
        {
            while (queue.Count > 0)
            {
                signal.Set();
                Thread.Sleep(5);
            }
        }

        private void MonitorQueue()
        {
            while (true)
            {
                // wait for work to show up
                signal.WaitOne(TimeSpan.FromSeconds(3));
                {
                    // process each data block in the queue
                    T data;

                    while (queue.TryDequeue(out data))
                    {
                        // write the data
                        this.writer(data);
                    }
                }

                if (quit && queue.Count == 0)
                {
                    break;
                }

                // Prevent very "chatty" waits. It's ok to accumulate writes as long as we can keep up
                // the burst of writes. Otherwise single writes will result in kernel transitions most times
                // Could also use a lighter wait algorithm (SpinLocks / Monitor.Pulse or similar) but a Thread.Sleep is 
                // much simpler and a good compromise
                Thread.Sleep(5);
            }
        }
    }

    public static class Log
    {
        private static string filename;
        private static SynchronizedIO<string> writer;
        private static StreamWriter file;

        public static void Initialize(string filename)
        {
            if (Log.filename != null)
            {
                throw new InvalidOperationException("Log already initialized with filename " + Log.filename);
            }

            if (File.Exists(filename))
            {
                File.Move(filename, filename + "." + Environment.TickCount.ToString() + Path.GetExtension(filename));
            }

            File.WriteAllText(filename, "");

            Log.filename = filename;
            var f = new FileStream(Log.filename, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
            Log.file = new StreamWriter(f);
            Log.file.AutoFlush = true;

            Log.writer = new SynchronizedIO<string>(WriterProc);
        }

        public static void Write(string message)
        {
            Log.writer.Enqueue(message);
            Console.Write(message);
        }

        public static void WriteLine(string message)
        {
            Log.writer.Enqueue(DateTime.Now + "\t" + message + "\r\n");
            Console.WriteLine(@message);
        }

        public static void WriteLine(string message, params object[] args)
        {
            if (Log.filename == null)
            {
                throw new InvalidOperationException("Log not initialized.");
            }

            string s = message;
            if (args.Length > 0)
            {
                s = string.Format(message, args);
            }

            WriteLine(s);
        }

        public static void Flush()
        {
            Log.writer.Flush();
            Log.writer.Dispose();
            Log.file.Close();
        }

        private static void WriterProc(string data)
        {
            file.Write(data);
        }

        public static void StoreSnapshotAs(string snapshotFilename)
        {
            Log.writer.Flush();

            string text = "";
            using (var f = new FileStream(Log.filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
            using (var sr = new StreamReader(f))
            {
                text = sr.ReadToEnd();
            }

            File.WriteAllText(snapshotFilename, text);
        }
    }
}

以上是关于csharp 用于CLI的多线程记录器的主要内容,如果未能解决你的问题,请参考以下文章

通过gevent实现单线程下的多socket并发

用于理解 Java 中的多线程的简单任务

用于图像处理的基于生产者-消费者的多线程

用于向 Web 服务发出 http post 请求的多线程

csharp .NET文件,用于显示如何使用和配置TraceSource进行日志记录。

Java中的多线程矩阵乘法