【问题标题】:Multiple readers and multiple writers(i mean multiple) synchronization多个读者和多个作者(我的意思是多个)同步
【发布时间】:2013-06-22 15:00:48
【问题描述】:

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

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

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

你们知道任何现有的方案吗?

谢谢,

【问题讨论】:

  • 感觉就像我可以用两个读/写锁做一些事情。但是,我无法完全解决它。

标签: unix concurrency synchronization operating-system locking


【解决方案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 时,这意味着首先持有锁的人现在可以释放它。此解决方案的唯一不便之处在于,持有锁的线程必须保持活动状态,直到每个人都完成才能释放它。

【讨论】:

  • 如果第一次同时调用 read() 和 write(),您将输入两个 if 语句。换句话说,您允许同时阅读和写作
【解决方案2】:

如果您使用的是 pthreads,请查看this question 中的同步方法。

您可以对两个变量 readerCountwriterCount 以及一个互斥锁使用类似的方法。 在阅读器线程中,您将锁定互斥锁并等待writerCount == 0。如果满足此条件,则将 readerCount 增加 1 并释放锁。然后你做阅读。完成后,再次锁定互斥体,减少 readerCount,发出条件更改信号并释放锁定。

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

【讨论】:

  • 谢谢尼夫。我是按照这些思路思考的。我已经在上面发布了我的答案。问题在于公平政策。
【解决方案3】:

我确实有一个类似 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();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多