螺纹安全无锁

时间:2013-03-04 23:36:27

标签: c# multithreading image-processing

我的成像库中有以下代码,它利用处理器列表动态操作HttpModule捕获的图像。

目前,每个处理器只创建一个实例,以便保持内存开销,并且每个处理器都具有可写属性,这有助于确定处理每个匹配的查询字符串参数的顺序,并将解析后的值存储到进程中。

正如您所看到的,我目前正在lock语句中包含方法功能,以防止HttpModule中的不同线程覆盖处理器属性,但我知道这可能会成为瓶颈。我想知道的是:是否有一种设计模式或方法可以使我的处理器线程安全而无需锁定?

public static ImageFactory AutoProcess(this ImageFactory factory)
{
    if (factory.ShouldProcess)
    {
        // TODO: This is going to be a bottleneck for speed. Find a faster way.
        lock (SyncLock)
        {
            // Get a list of all graphics processors that 
            // have parsed and matched the querystring.
            List<IGraphicsProcessor> list =
              ImageProcessorConfig.Instance.GraphicsProcessors
              .Where(x => x.MatchRegexIndex(factory.QueryString) != int.MaxValue)
              .OrderBy(y => y.SortOrder)
              .ToList();

            // Loop through and process the image.
            foreach (IGraphicsProcessor graphicsProcessor in list)
            {
                factory.Image = graphicsProcessor.ProcessImage(factory);
            }
        }
    }

    return factory;

}

2 个答案:

答案 0 :(得分:2)

您可能会对生产者消费者队列感兴趣。通常,您的HttpModule将接收事件(生产者)并将它们排队到IGraphicsProcessor(消费者)的一个或多个实例。

这是规范,最简单的生产者/消费者队列实现:http://www.albahari.com/threading/part4.aspx#_Wait_Pulse_Producer_Consumer_Queue

如果您打算消除锁定,则应使用无锁队列实现(例如.NET 4.0中的System.Collections.Concurrent.ConcurrentQueue<T>)体验生产者/消费者队列。

答案 1 :(得分:2)

要么你需要通过不使用多个处理器来降低内存压力(然后你需要允许至少一个给定的处理器完成它的当前工作),或者你需要完全并发。

除非有明确的理由不这样做,否则我会允许每个图像处理器的多个实例。确保处理器尽早释放对其所作用数据的引用,以使GC能够以最佳方式运行。这具有简单的优点,并且具有良好的CPU核心利用率。

如果有明确的理由只允许每个处理器的一个实例,则可以通过避免锁定当前的情况来改进代码,直到所有处理器完成其工作。相反,一旦当前项完成,您可以有一种机制来请求每个处理器,您需要处理下一个项目。 @ anthony建议使用生产者/消费者模式似乎是一个可靠的解决方案。请记住,使用这种方法,您仍然会遇到每个过滤器的吞吐量瓶颈,并且您可能无法以最佳方式利用所有CPU内核。