0

我不确定是否使用 Mutex 或 Semaphore 或其他一些工具。

这是我的场景:在多线程环境中,某些事件会导致将图像写入磁盘。此图像在事件处理程序中生成。

问题是,事件 A 会导致写入图像 A.png,而事件 B 会导致写入名为 B.png 的图像。

如果这些事件同时发生,则可以保存图像(尽管磁盘显然不能很好地处理并行写入)但这是一个有效的场景。

但是有时会多次触发事件 A。这也是有效的,但为相同的文件名调用 image.Save 会导致通用 GDI 错误。

如何在不锁定每个线程的情况下使用工具锁定 .Save(...) 调用(例如使用 lock 关键字)

我想到了一个手工制作的解决方案,其中处理程序将文件名写入查找表,然后写入文件。其他处理程序需要检查查找,然后执行一些 Thread.Sleep 或类似操作。但这看起来确实像资源锁定的幼稚方法。

对于这种锁定“虚拟”资源的自定义锁,是否有适当的方法?(虚拟的,因为它在锁定时可能不存在)。

更新和编辑: 图像生成执行一些数字运算,因此包含在任务中。一个典型的场景是总是同时创建多个图像以利用 Thread.Pool。我知道作业队列可以解决问题,但它会删除并行执行。如果我手动将作业分配给 n 线程(这意味着编写我自己的池,对吗?)我仍然会遇到两个线程可能尝试写入同一个文件的问题。

事件源是不可靠的,因此它可能会使用同一个文件多次调用写入操作,但实际上只要一个“图像 A”生成正在工作或尚未开始第二个、第三个或任何事件处理都可以忽略。

4

2 回答 2

4

创建一个Queue<MyImageWriteTaskClass>. Spawn 线程,检查队列是否已填充,如果是,则将队列的内容逐个出列,将图像写入磁盘,直到队列为空,然后线程继续等待,直到有新项目入队。当事件被触发时,只需将一个新的MyImageWriteTaskClass.

假设您使用线程安全队列,除了围绕出队和入队的单个锁定之外,不需要其他锁定。如果您的硬件跟不上,或者您有磁盘缓存,您可能需要限制磁盘保存操作。

或者,如果您想使用最新最好的工具,您可以查看使用 IObservable 并处理可观察的 Save 事件流。这样做的另一个好处是大大简化了诸如节流之类的非常花哨的机制。

于 2013-10-01T16:21:32.620 回答
2

除了马克的回答:您可以使用BlockingCollection<T>类,它实现了生产者-消费者模式。请参阅文档示例部分中的ConsumingEnumerableDemo类。

于 2013-10-01T16:38:01.760 回答