无锁的线程安全队列 - 需要咨询
-
20-09-2019 - |
题
我需要设计一个线程安全记录。我的记录器必须有一个简单的队列中记录文本日志()方法。另外一个记录器必须是无锁 - 让其他线程可以登录的消息不锁定记录。我需要设计一个工作线程必须等待 对于一些同步事件,然后登录使用标准的.NET日志队列中的所有邮件(不是线程安全的)。所以,我所感兴趣的是工作线程的同步 - 和日志功能。下面是我设计的类的草图。我想我必须在这里使用Monitor.Wait /脉冲或其他任何方式挂起和恢复工作线程。我不;吨要花费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
}
}
}
解决方案
“无锁的”并不意味着线程将不会彼此阻塞。这意味着,他们通过非常高效,而且非常棘手的机制阻止对方。只需要非常高的性能场景和连专家搞错了(很多)。
最好的建议:忘记“无锁”,只是用一个“线程安全”的队列
我建议从当前页一>
和它的选择,包括在类本身ThreadRoutine
(消费者)的问题。
要你问题的第二部分,要看是什么“的一些同步事件”到底是。如果你要使用一个方法调用,然后让那个启动一锤子线。如果你想等待一个信号灯比的不的使用监控和脉搏。他们是不可靠的在这里。使用的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
}
}
}
}
讨论的部分似乎是处理所述队列(标记***
)时该怎么办。您可以锁定队列和过程中的所有项目,在此期间,新条目的添加将被阻止(长),或锁定,并通过唯一锁(非常)不久每次检索条目之一。我已经ADDE是最后一个场景。
摘要:你不想要一个无锁的解决方案,但一个块免费的。块免费不存在,你将不得不解决的东西,块尽可能少。 MYS样品的最后一次迭代(不完全统计)显示如何锁定只围绕加入和离开队列调用。我认为,这将是速度不够快。
其他提示
向你展示了你的分析器,您遇到通过使用简单lock
声明一个大的开销?无锁编程是很难得到正确的,如果你真的需要它,我会建议服用从可靠的来源存在的东西。
这并不难,如果你有原子操作,使这个无锁的。以一个单向链表;你只需要在头指针。
日志功能:结果 1.准备本地日志项(节点与测井组)。结果 2.设置本地节点的下一个指针为头即可。结果 3. ATOMIC:比较头与本地节点的下一个,如果相等,则更换的头与本地节点的地址结果。 4.如果操作失败,则重复从步骤2,否则,产品可在“队列”。
工人:结果 1.复制的头强>本地。结果 2.的原子强>比较的头强>当地一个,如果相等,则替换的头强>使用NULL结果。 3.如果操作失败,请重复步骤1点击 4.如果它成功了,处理的物品;其是现在本地和移出“排队”的。