想象一下,我们有0
到n-1
的整数(让我们说我们有n
个图像并使用此索引识别它们)和一对带有这些整数。在这里我们如何创建这些对并不是很重要,但只是为了可视化问题,我们可以说对是那些具有共同区域的图像。
我们的任务是使用多个线程处理所有可用对。如果要求只是每个对都可以被一个线程占用,那么任务就很简单:我们可以使用互斥对象的每个元素。但在我的情况下,情况更加困难:如果某个线程处理一对(m,n)
,则另一个线程不能使用由m
或n
组成的任何一对。
对每个图像使用互斥锁的简单解决方案是不足的。例如,我们假设我们有图片0,1,2,3
和对(0,1)
,(1,2)
,(2,3)
,(3,0)
。如果算法对一对使用互斥,然后为每个图像使用两个互斥,则可能出现死锁:th_0
将处理对(0,1)
,th_1
- 对(1,2)
,{{ 1}} - 对th_2
和(2,3)
- 对th_3
。然后每个线程将使用互斥体作为单个图像。
(3,0)
th_0: lock 0, lock 1
th_1: lock 1, lock 2
th_2: lock 2, lock 3
th_3: lock 3, lock 0
将锁定图片th_0
,0
会锁定图片th_1
,但1
会停止,因为它会尝试锁定图片{{1已经锁定的。所有其他线程都会发生同样的情况。
似乎为了实现目标,每个线程必须用对锁定整个向量以避免死锁,这似乎不是一个好的解决方案。这是正确的吗?这个问题有更好的解决方案吗?我想到的唯一解决方案是将互斥锁用于图像以及线程优先级信息。例如,如果第二个图像被锁定,则线程将检查锁定线程的线程ID是否更高,然后它应该释放第一个图像上的锁并继续。它会工作还是我可以再次陷入僵局?
答案 0 :(得分:5)
当持有资源R1的线程T1尝试获取R2而T2持有R2尝试获取R1时,发生死锁。完全是你的情况。
打破僵局的通常方法是始终以相同的顺序获取资源(如果可能的话)。
在您的情况下,“相同订单”是一个简单的解决方案:首先锁定min(first, second)
然后锁定另一个。所以当你在试图锁定“较小”的时候持有“更大”的资源时,你将永远不会结束。
虽然这个解决方案很简单,但它可能不是最理想的,取决于图像处理需要很长时间并且线程经常彼此等待时的争用。
答案 1 :(得分:0)
即使没有死锁,也可能阻塞许多线程等待下一个资源。这可以将并行度降低到最佳水平以下。要提高并行度,必须增加线程数,这需要大量内存。
我看到了两种方法:1)使用一些异步任务并行库,每个任务是处理一些(n,m)对。由于任务使用少量内存,因此您可以在启动时生成所有任务。大量任务承诺高水平的并行性。
然而,最好的结果是动态计算提供最高并行度水平的对的序列。它可以是在专用线程上运行的算法。它从生成N对(0,1),(2,3),...(N-2,N-1)开始。然后它等待下一个任务的结束,并查看是否可以将其他任务提交给执行者。