1

我正在开发一个需要读/写锁变体的功能,它可以允许并发多个写入者。

标准读/写锁允许多个读取器或单个写入器同时运行。我需要一个可以同时允许多个读取器或多个写入器的变体。因此,它永远不应该同时允许一个读者和一个作者。但是,允许同时允许多个写入者或同时允许多个读取者是可以的。

我希望我很清楚。到目前为止,我找不到任何现有的算法。我可以使用一些队列等来想出几种方法来做到这一点。但是,除非不存在,否则我不想冒险自己去做。

大家知道现有的方案吗?

谢谢,

4

3 回答 3

1

您正在寻找的概念是可重入锁。如果锁已被占用,您需要能够尝试获取锁并且不会被阻塞(这称为可重入锁)。在 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();
   }
  }

这里发生了什么:首先,您检查您的锁是否已锁定,以了解您是否可以执行您将要执行的操作。如果它被锁定,则意味着您无法读取或写入,因此您使用 lock 将自己置于等待状态,并在再次释放锁时重新调用相同的操作。

如果它没有被锁定,那么你使用 tryLock 锁定另一个动作(如果你要读你锁定写,反之亦然)。tryLock 不会阻塞,如果它已经被锁定,那么几个写者可以同时写,几个读者可以同时读。当与您执行相同操作的线程数达到 0 时,这意味着首先持有锁的人现在可以释放它。这个解决方案唯一的不便是持有锁的线程必须保持活动状态,直到每个人都完成才能释放它。

于 2013-06-22T16:31:30.623 回答
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();
    }
}
于 2013-06-22T16:22:20.477 回答
0

如果您使用的是 pthreads,请查看此问题中的同步方法。

readerCount您可以对两个变量和writerCount一个互斥锁使用类似的方法。在阅读器线程中,您将锁定互斥锁并等待writerCount == 0. 如果满足此条件,则将readerCount1 递增并释放锁。然后你做阅读。完成后,再次锁定互斥锁,递减readerCount,表示条件更改并释放锁定。

编写器线程遵循相同的逻辑,但等待条件并改为readerCount == 0递增/递减。writerCount

于 2013-06-22T15:28:50.663 回答