【发布时间】:2016-05-19 18:37:42
【问题描述】:
我正在使用pthreads 进行一个项目,我自己实现了 Readers Writer Lock,它具有以下方法:
- 阅读器锁定(可同时阅读多个)
- 写者锁(只有一个人可以写)
- 解锁(读写器)
我已经测试过了,效果很好,我的问题更符合逻辑, 在我的程序中,我希望几个线程对特定范围内的数字进行一些测试,如果找到一个符合我的标准的数字,我希望他们将它们添加到一个共享资源中,该资源是一个数组。
如果该数字已被另一个线程找到并且存在于数组中,则继续搜索。
这是我的算法的伪代码:
X = lowest number to search, X' = highest number to search,
func = the test for the number, ARR = the array shared between the threads,
RWL_R = Lock for reader, RWL_W Lock for writer, RWL_U = Unlock.
FOR each NUM from X to X' DO:
IF func(NUM) = true DO:
FOR each cell of ARR DO:
RWL_R // lock for reader since i'm reading from ARR
IF ARR[cell] contains NUM DO:
RWL_U // unlock since no longer reading from ARR
skip to the next iteration of the first FOR loop
ENDIF
END FOR
RWL_U // unlock since no longer reading from ARR
////// PROBLEM HERE ////////
RWL_W // lock to write to array since for loop ended without finding the same NUM
ARR[cell] <- NUM
RWL_U // unlock since finished writing into array
END IF
END FOR
正如您所见,逻辑很好,因为我用丑陋的大写字母“PROBLEM HERE”标记了那条小线。在读取器解锁和写入器锁定之间的小间隙内,可能(并且确实)会发生竞争条件。
所以我有两个可能的结果:
-
(善)
- Thread_A 找到数字 N,锁定数组以供读取。
- Thread_B 找到相同的数字 N,等待检查数组,但它当前被 Thread_A 锁定。
- Thread_A 完成遍历数组并且数字 N 不存在,解锁锁并作为写入器再次锁定它,将 N 添加到数组中,解锁锁并完成他的工作。
- Thread_B 现在可以检查数组,编号 N 在那里,所以它跳到编号 N2,其余的工作正常。
-
(坏的)
- Thread_A 找到数字 N,锁定数组以供读取。
- Thread_B 找到相同的数字 N,等待检查数组,但它当前被 Thread_A 锁定。
- Thread_A 完成遍历数组并且数字 N 不存在,解锁锁。
- Thread_B 接管锁并将其锁定为读取器,检查数组和数字 N 仍然不存在(Thread_A 尚未添加它)。
Thread_B 解锁。
现在 Thread_A 或 Thread_B 锁定写操作的锁,添加数字 N,解锁锁并完成。
- 等待的线程现在锁定锁,添加相同的数字 N,解锁并完成。
所以我现在正试图找到解决问题的最佳逻辑方法,我只能在检查数组时考虑锁定作为写入器,直到完成写入才解锁它,或者创建一个“原子地切换”的方法” 从读取器锁到写入器锁,但这是一种“作弊”,而不是使用应该使用的“Readers Writer Lock”机制。
在这里使用它有什么更好的逻辑方式?
【问题讨论】:
标签: c arrays linux multithreading pthreads