2009-06-30 87 views
2

所以我有一个静态类,应该用作日志文件管理器,能够将“消息”(字符串)添加到队列对象,并将消息推送到文件。麻烦的是,许多不同的线程应该排队,并且作者也需要异步。目前,当我插入队列时,我还检查是否写作者(布尔检查),如果不是,我设置了布尔然后开始写入,但我得到了关于文件访问的间歇性IO异常,然后有时候写作行为会更加奇怪。多线程文件写队列

有人想帮我一下吗?

回答

2

听起来像队列正在驱动文件写入操作。我建议您反转控制关系,以便写入者驱动进程并检查队列是否工作。

实现此目的的最简单方法是向写入程序添加轮询机制,在该写入程序中它会定期检查队列的工作情况。

或者,您可以创建一个可观察的队列类,在队列从空过渡时通知订阅者(作者):订阅作者可以开始工作。 (此时,作者还应退订队列的广播,或以其他方式更改对队列警报的反应方式。)

作业完成后,作者将检查队列以进行更多工作。如果没有其他工作要做,它会进入睡眠状态并继续轮询或进入睡眠状态并重新订阅队列的警报。

由于Irwin noted in his answer,你还需要使用由Queue类的Synchronized方法提供的线程安全的包装或手动如果将多个线程从中读取和写入到它(as in SpaceghostAli's example)同步访问你的Queue

2

您应该同步您的队列。让多个线程发送到队列并从队列中读取单个线程并写入文件。

public void Log(string entry) 
{ 
    _logMutex.WaitOne(); 
    _logQueue.Enqueue(entry); 
    _logMutex.ReleaseMutex(); 
} 

private void Write() 
{ 
    ... 
    _logMutex.WaitOne(); 
    string entry = _logQueue.Dequeue(); 
    _logMutex.ReleaseMutex(); 

    _filestream.WriteLine(entry); 
    ... 
} 
1

如果你不想调整你的代码大大就像我在我的其他回答表明,你可以试试这个,它假设你LogManager类有:

  • 静态线程安全队列,_SynchronizedQueue
  • 静态对象写入时来锁定,_WriteLock

并且这些方法:

public static void Log(string message) { 
    LogManager._SynchronizedQueue.Enqueue(message); 
    ThreadPool.QueueUserWorkItem(LogManager.Write(null)); 
} 

// QueueUserWorkItem accepts a WaitCallback that requires an object parameter 
private static void Write(object data) { 
    // This ensures only one thread can write at a time, but it's dangerous 
    lock(LogManager._WriteLock) { 
     string message = (string)LogManager._SynchronizedQueue.Dequeue(); 
     if (message != null) { 
      // Your file writing logic here 
     } 
    } 
} 

只有一个问题:上述Write方法中的锁定语句将保证一次只能有一个线程写入,但这是危险的。尝试写入文件时会出现很多错误,并且您不希望无限期地保持(阻止)线程池线程。因此,你需要使用一个同步对象,可以让你指定超时,如Monitor,并重写你Write方法是这样的:

private static void Write() { 
    if (!Monitor.TryEnter(LogManager._WriteLock, 2000)) { 
     // Do whatever you want when you can't get a lock in time 
    } else { 
     try { 
     string message = (string)LogManager._SynchronizedQueue.Dequeue(); 
     if (message != null) { 
      // Your file writing logic here 
     } 
     } 
     finally { 
     Monitor.Exit(LogManager._WriteLock); 
     } 
    } 
} 
1

让我在不同的层面解决的问题:

如果你正在编写一个商业应用程序,那么你应该把重点放在业务逻辑部分而不是基础代码上,如果这个代码已经可用,测试并部署到多个生产站点(照顾你的NFR),那么更是如此。

我确定你知道伐木框架的存在ks像log4net和其他http://csharp-source.net/open-source/logging

在您推出自己的记录器之前,您是否给过这些机会?

将此选项添加到您正在撰写的企业的技术架构师,并看到她的想法。

干杯