Cap*_*mic 2 c# logging thread-safety lock-free
我需要设计一个线程安全的记录器。我的记录器必须具有一个Log()方法,该方法只是将要记录的文本排队。另外,记录器必须是无锁的-这样其他线程就可以在不锁定记录器的情况下记录消息。我需要设计一个工作线程,该线程必须等待一些同步事件,然后使用标准的.NET日志记录(不是线程安全的)记录队列中的所有消息。因此,我感兴趣的是工作线程和Log函数的同步。下面是我设计的课程的草图。我想我必须在这里使用Monitor.Wait / Pulse或任何其他方式来挂起和恢复工作线程。我不想在没有记录器的工作时花费CPU周期。
让我换一种说法-我想设计一个不会阻止使用它的调用者线程的记录器。我有一个高性能的系统-这是必需的。
class MyLogger
{
// This is a lockfree queue - threads can directly enqueue and dequeue
private LockFreeQueue<String> _logQueue;
// worker thread
Thread _workerThread;
bool _IsRunning = true;
// this function is used by other threads to queue log messages
public void Log(String text)
{
_logQueue.Enqueue(text);
}
// this is worker thread function
private void ThreadRoutine()
{
while(IsRunning)
{
// do something here
}
}
}
Run Code Online (Sandbox Code Playgroud)
“无锁”并不意味着线程不会互相阻塞。这意味着它们通过非常有效但又非常棘手的机制相互阻止。仅在非常高性能的情况下才需要,甚至专家都会弄错(很多)。
最佳建议:忘记“无锁”,而只使用“线程安全”队列。
我会推荐此页面上的“阻止队列” 。
将ThreadRoutine(消费者)包括在类本身是一个选择问题。
在问题的第二部分,它取决于确切的“某些同步事件”。如果要使用Method调用,则让该线程启动单发线程。如果您要等待信号量,则不要 使用Monitor and Pulse。他们在这里不可靠。使用一个AutoResetEvent / ManualResetEvent。
如何浮出水面取决于您要如何使用它。
您的基本成分应如下所示:
class Logger
{
private AutoResetEvent _waitEvent = new AutoResetEvent(false);
private object _locker = new object();
private bool _isRunning = true;
public void Log(string msg)
{
lock(_locker) { _queue.Enqueue(msg); }
}
public void FlushQueue()
{
_waitEvent.Set();
}
private void WorkerProc(object state)
{
while (_isRunning)
{
_waitEvent.WaitOne();
// process queue,
// ***
while(true)
{
string s = null;
lock(_locker)
{
if (_queue.IsEmpty)
break;
s = _queue.Dequeu();
}
if (s != null)
// process s
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
讨论的一部分似乎是处理Queue(标记为***)时的处理方式。您可以锁定队列并处理所有项目,在此期间,新条目的添加将被阻止(较长),或者一次又一次地锁定和检索条目,并且每次仅锁定(非常)一次。我已经添加了最后一种情况。
总结:您不想要无锁解决方案,而是无块解决方案。无障碍不存在,您将不得不解决一些尽可能少的障碍。mys示例的最后一次迭代(未完成)显示了如何仅锁定Enqueue和Dequeue调用。我认为那将足够快。
| 归档时间: |
|
| 查看次数: |
3327 次 |
| 最近记录: |