无锁线程安全队列 - 需要咨询 [英] Lock-free thread-safe queue - need advice

查看:182
本文介绍了无锁线程安全队列 - 需要咨询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要设计一个线程安全记录。我的记录必须有一个简单的队列中记录的文本日志()方法。另外一个记录器必须是无锁 - 使其他线程可以登录的消息不锁定记录。我需要设计一个工作线程必须等待
对于一些同步事件,然后登录使用标准的.NET日志记录队列中的所有消息(非线程安全的)。所以,我所感兴趣的是工作线程同步 - 和日志功能。下面是我设计的类的草图。我想我一定在这里使用Monitor.Wait /脉冲或其他任何方式挂起和恢复工作线程。我不;吨要花费CPU周期时,有对记录器没有工作。



让我换一种方式 - 我想设计一个记录器即会不会阻止呼叫者使用它的线程。我有一个高性能系统 - 这是一个要求。

 类MyLogger 
{
//这是一个lockfree队列 - 线程可以直接入队和出队
私人LockFreeQueue<串GT; _logQueue;
//工作者线程
螺纹_workerThread;
布尔_IsRunning = TRUE;

//这个函数是用来被其它线程队列日志消息
公共无效日志(字符串文本)
{
_logQueue.Enqueue(文本);
}

//这是工作线程功能
私人无效ThreadRoutine()
{
,而(IsRunning)
{
//做的东西在这里
}
}
}


解决方案

无锁并不意味着线程不会阻止对方。这意味着,他们通过非常高效,而且非常棘手的机制阻止对方。只需要非常高的性能的情景,甚至专家搞错了(很多)



最好的建议:忘了无锁,只是用一个线程安全的队列中。



我会建议,从此页面



和这是一个选择的问题,包括在 ThreadRoutine 中的类本身(消费者)。



要你问题的第二部分,要看是什么的一些同步事件到底是。如果你要使用的方法调用,然后让那开始以一杆线程。如果你想等待一个信号灯比的的使用监控和脉搏。它们是不可靠的在这里。 。使用的AutoResetEvent / ManualResetEvent的结果
如何表面取决于你想如何使用它



您的基本成分应该是这样的:

 类的Logger 
{
私人的AutoResetEvent _waitEvent =新的AutoResetEvent(假);
私有对象_locker =新的对象();
私人布尔_isRunning = TRUE;

公共无效日志(string信息)
{
锁(_locker){_queue.Enqueue(MSG); }
}

公共无效FlushQueue()
{
_waitEvent.Set();
}

私人无效WorkerProc(对象状态)
{
,而(_isRunning)
{
_waitEvent.WaitOne();
//进程队列,
// ***
,而(真)
{
字符串s = NULL;
锁(_locker)
{
如果(_queue.IsEmpty)
中断;
S = _queue.Dequeu();
}
如果(S!= NULL)
//方法S
}
}
}
}

讨论的一部分似乎是在处理队列(在做什么标记 *** )。您可以锁定队列和过程中的所有项目,在此期间,新条目的添加将被封锁(长),或锁定和唯一锁(非常)不久每次检索条目之一。我已经ADDE的最后一个场景



摘要:你不想要一个无锁的解决方案,但一个块免费的。块自由不存在,你将不得不解决的东西,阻止尽可能少。角样品的最后一次迭代(不完全统计)显示如何锁定只围绕入队和出列呼叫。我认为这将是速度不够快。


I need to design a thread-safe logger. My logger must have a Log() method that simply queues a text to be logged. Also a logger must be lock-free - so that other thread can log messages without locking the logger. I need to design a worker thread that must wait for some synchronization event and then log all messages from the queue using standard .NET logging (that is not thread-safe). So what i am interested in is synchronization of worker thread - and Log function. Below is a sketch of the class that i designed. I think I must use Monitor.Wait/Pulse here or any other means to suspend and resume worker thread. I don;t want to spend CPU cycles when there is no job for logger.

Let me put it another way - I want to design a logger that will not block a caller threads that use it. I have a high performance system - and that is a requirement.

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
 }
}    
}

解决方案

"lock-free"does not mean that threads won't block each other. It means that they block each other through very efficient but also very tricky mechanisms. Only needed for very high performance scenarios and even the experts get it wrong (a lot).

Best advice: forget "lock-free"and just use a "thread-safe" queue.

I would recommend the "Blocking Queue" from this page.

And it's a matter of choice to include the ThreadRoutine (the Consumer) in the class itself.

To the second part of your question, it depends on what "some synchronization event" exactly is. If you are going to use a Method call, then let that start a one-shot thread. If you want to wait on a Semaphore than don't use Monitor and Pulse. They are not reliable here. Use an AutoResetEvent/ManualResetEvent.
How to surface that depends on how you want to use it.

Your basic ingredients should look like this:

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
            }
        } 
    }
}

Part of the discussion seems to be what to do when processing the Queue (marked ***). You can lock the Queue and process all items, during which adding of new entries will be blocked (longer), or lock and retrieve entries one by one and only lock (very) shortly each time. I've adde that last scenario.

A summary: You don't want a Lock-Free solution but a Block-Free one. Block-Free doesn't exist, you will have to settle for something that blocks as little as possible. The last iteration of mys sample (incomplete) show how to only lock around the Enqueue and Dequeue calls. I think that will be fast enough.

这篇关于无锁线程安全队列 - 需要咨询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆