我正在开发一种需要读/写锁定变体的功能,可以允许并发多个写入器。
标准读/写锁允许多个读取器或单个写入器同时运行。我需要一个可以同时允许多个读者或多个作者的变体。因此,它不应该同时允许读者和作者。但是,可以同时允许多个作者或同时允许多个读者。
我希望我很清楚。到目前为止我找不到任何现有的算法。我可以想办法使用一些队列等来做这些事情。但是,我不想冒险自己做,除非不存在。
你们知道现有的计划吗?
谢谢,
答案 0 :(得分:0)
如果您使用的是pthread,请查看this question中的同步方法。
您可以使用两个变量readerCount
和writerCount
以及互斥锁的类似方法。
在读者线程中,您将锁定互斥锁并等待writerCount == 0
。如果满足条件,则将readerCount
递增1并释放锁定。然后你做阅读。完成后,再次锁定互斥锁,递减readerCount
,指示条件发生变化并释放锁定。
编写器线程遵循相同的逻辑,但是等待条件readerCount == 0
并递增/递减writerCount
。
答案 1 :(得分:0)
我确实有一个Nifs评论的解决方案。我在下面发布了我的解决方案。问题在于公平政策。饥饿很容易发生。在我的方法中,一种线程不太可能比其他线程。所以我只是优先考虑女孩。理想情况下,我们希望这是一个体面的公平政策。
/**
* RestRoomLock:
*
* This lock tries to simulate a gender based access to common rest room.
* It is okay to have multiple boys or multiple girls inside the room. But,
* we can't have boys and girls at the same time inside the room.
*
* This implementation doesn't really have proper fairness policy. For now,
* girls are being treated with priority as long as boys are being gentle,
* boyEntryBeGentle();
*
* @author bmuppana
*/
public class RestRoomLock {
int boysInside;
int girlsInside;
int girlsWaiting;
RestRoomLock() {
boysInside = girlsInside = girlsWaiting = 0;
}
public synchronized void boyEntry() {
while (girlsInside > 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
boysInside++;
}
public synchronized void boyEntryBeGentle() {
while (girlsInside + girlsWaiting > 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
boysInside++;
}
public synchronized void boyExit() {
boysInside--;
assert boysInside >= 0;
notifyAll();
}
public synchronized void girlEntry() {
girlsWaiting++;
while (boysInside > 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
girlsWaiting--;
girlsInside++;
}
public synchronized void girlExit() {
girlsInside--;
assert girlsInside >= 0;
notifyAll();
}
}
答案 2 :(得分:0)
您正在寻找的概念是重入锁定。如果已经锁定,则需要能够尝试获取锁定并且不会被阻止(这称为可重入锁定)。在java中有一个可重入锁的本机实现,所以我将用Java来说明这个例子。 (http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html)。
因为当使用tryLock()时,如果锁定不可用,则不会阻止您的编写器/阅读器继续。但是,当您确定没有人正在读/写时,您只想释放锁定,因此您需要保留读者和作者的数量。您将需要同步此计数器或使用允许原子递增/递减的本机atomicInteger。对于这个例子,我使用了原子整数。
Class ReadAndWrite {
private ReentrantLock readLock;
private ReentrantLock writeLock;
private AtomicInteger readers;
private AtomicInteger writers;
private File file;
public void write() {
if (!writeLock.isLocked()) {
readLock.tryLock();
writers.incrementAndGet(); // Increment the number of current writers
// ***** Write your stuff *****
writers.decrementAndGet(); // Decrement the number of current writers
if (readLock.isHeldByCurrentThread()) {
while(writers != 0); // Wait until all writers are finished to release the lock
readLock.unlock();
}
} else {
writeLock.lock();
write();
}
}
public void read() {
if (!readLock.isLocked()) {
writeLock.tryLock();
readers.incrementAndGet();
// ***** read your stuff *****
readers.decrementAndGet(); // Decrement the number of current read
if (writeLock.isHeldByCurrentThread()) {
while(readers != 0); // Wait until all writers are finished to release the lock
writeLock.unlock();
}
} else {
readLock.lock();
read();
}
}
这里发生了什么:首先,检查您的锁是否已锁定,以了解您是否可以执行您要执行的操作。如果它被锁定则表示您无法读取或写入,因此您使用锁定使自己处于等待状态,并在再次释放锁定时重新调用相同的操作。
如果它没有被锁定,那么你使用tryLock锁定另一个动作(如果你要读锁定写,反之亦然)。 tryLock如果已经锁定则不会阻塞,因此几个编写者可以同时写入并且几个读者可以同时读取。当你做同样事情的线程数达到0时,这意味着谁拥有锁头的人现在可以释放它。这个解决方案唯一的不便是持有锁的线程必须保持活着,直到每个人都完成才能释放它。