优化读/写锁的实现

时间:2022-03-24 09:34:51

I am currently implementing a read/write lock using boost library, without using shared_lock and unique_lock. I have already read some related questions (e.g., How would a readers/writer lock be implemented in C++11?), but I still want to optimize the implementation.

我目前正在使用boost库实现读/写锁,而不使用shared_lock和unique_lock。我已经阅读了一些相关的问题(例如,如何在C ++ 11中实现读者/作者锁定?),但我仍然希望优化实现。

Here is my code:

这是我的代码:

enum LockType { NO_LOCK, READ_LOCK, WRITE_LOCK, INC_LOCK };
boost::mutex mutex_;
boost::condition condition_;
LockType lock_;
size_t owner_count_;

void AcquireReadLock() {
    mutex_.lock();
    while (lock_ != NO_LOCK && lock_ != READ_LOCK){
        condition_.wait(mutex_);
    }
    // if there is no lock, then acquire read lock.
    if (lock_ == NO_LOCK) {
        lock_ = READ_LOCK;
        ++owner_count_;
        mutex_.unlock();
        return;
    }
    else {
        // if there is read lock, then still acquire read lock.
        assert(lock_ == READ_LOCK);
        ++owner_count_;
        mutex_.unlock();
        return;
    }
}

void AcquireWriteLock() {
    mutex_.lock();
    while (lock_ != NO_LOCK){
        condition_.wait(mutex_);
    }
    // if there is no lock, then acquire write lock.
    assert(lock_ == NO_LOCK);
    lock_ = WRITE_LOCK;
    mutex_.unlock();
    return;
}

void ReleaseReadLock() {
    mutex_.lock();
    --owner_count_;
    if (owner_count_ == 0) {
        lock_ = NO_LOCK;
    }
    mutex_.unlock();
    // is it correct to use notify_all?
    condition_.notify_all();
}

void ReleaseWriteLock() {
    mutex_.lock();
    lock_ = NO_LOCK;
    mutex_.unlock();
    // is it correct to use notify_all?
    condition_.notify_all();
}

The problem is:

问题是:

  1. whether I should use notify_all when releasing the lock? According to the document, once a thread gets notified, it will reacquire the lock. If using notify_all, then multiple threads can reacquire the same lock. What will happen then? And whether will a thread acquire the lock before checking the condition (i.e., lock_!=NO_LOCK && lock_!=READ_LOCK)?

    在释放锁时我是否应该使用notify_all?根据该文档,一旦线程得到通知,它将重新获取锁。如果使用notify_all,则多个线程可以重新获取相同的锁。那会发生什么?并且在检查条件之前是否线程获取锁(即,锁_!= NO_LOCK && lock _!= READ_LOCK)?

  2. how can I optimize the program? obviously, when releasing a read lock, we only need to notify the threads that attempt to acquire the write lock, since read never blocks read. So how to implement this idea?

    我该如何优化程序?显然,当释放读锁时,我们只需要通知尝试获取写锁的线程,因为read永远不会阻塞读。那么如何实现这个想法呢?

Thanks in advance for your kind help!

在此先感谢您的帮助!

2 个解决方案

#1


  1. whether I should use notify_all when releasing the lock? According to the document, once a thread gets notified, it will reacquire the lock. If using notify_all, then multiple threads can reacquire the same lock. What will happen then? And whether will a thread acquire the lock before checking the condition (i.e., lock_!=NO_LOCK && lock_!=READ_LOCK)?
  2. 在释放锁时我是否应该使用notify_all?根据该文档,一旦线程得到通知,它将重新获取锁。如果使用notify_all,则多个线程可以重新获取相同的锁。那会发生什么?并且在检查条件之前是否线程获取锁(即,锁_!= NO_LOCK && lock _!= READ_LOCK)?

Yes, you should use notify_all when releasing the lock. All condition_ waiting for the mutex_ will be waked one by one for they must lock the mutex_ firstly(this is done inner the condition_ wait operation).

是的,你应该在释放锁时使用notify_all。所有等待mutex_的condition_将被逐个唤醒,因为它们必须首先锁定mutex_(这是在condition_ wait操作内部完成的)。

  1. how can I optimize the program? obviously, when releasing a read lock, we only need to notify the threads that attempt to acquire the write lock, since read never blocks read. So how to implement this idea?
  2. 我该如何优化程序?显然,当释放读锁时,我们只需要通知尝试获取写锁的线程,因为read永远不会阻塞读。那么如何实现这个想法呢?

All threads waiting for mutex_ must be notified, for some writing threads may waiting for the read lock to be released.

必须通知所有等待mutex_的线程,因为某些写入线程可能正在等待释放读锁定。

I hope this will help you!

我希望这能帮到您!

#2


If using notify_all, then multiple threads can reacquire the same lock.

如果使用notify_all,则多个线程可以重新获取相同的锁。

No. Every notified thread will compete for lock acquirision, in the same way as mutex_.lock(). Even with notify_all, at most one thread can execute critical section's code at the time. So, using notify_all is perfectly correct.

不会。每个通知的线程都会以与mutex_.lock()相同的方式竞争锁定获取。即使使用notify_all,最多只有一个线程可以执行关键部分的代码。因此,使用notify_all是完全正确的。

  1. how can I optimize the program? obviously, when releasing a read lock, we only need to notify the threads that attempt to acquire the write lock, since read never blocks read. So how to implement this idea?
  2. 我该如何优化程序?显然,当释放读锁时,我们只需要通知尝试获取写锁的线程,因为read永远不会阻塞读。那么如何实现这个想法呢?

As read never blocks read, no read thread can wait() other read thread. So even with your current code ReleaseReadLock() can only notify write threads.

由于read永远不会阻塞读取,因此没有读取线程可以wait()其他读取线程。因此,即使使用当前代码,ReleaseReadLock()也只能通知写入线程。

Because of that, in ReleaseReadLock() you may safely use notify() instead of notify_all: no reason to awake all write threads, as only one of them can aqcuire your r/w lock.

因此,在ReleaseReadLock()中,您可以安全地使用notify()而不是notify_all:没有理由唤醒所有写入线程,因为只有其中一个可以获得您的r / w锁定。

As for other optimizations, you should better to fix artefacts, listed in this answer: https://*.com/a/12657243/3440745

至于其他优化,你应该更好地修复这个答案中列出的人工制品:https://*.com/a/12657243/3440745

#1


  1. whether I should use notify_all when releasing the lock? According to the document, once a thread gets notified, it will reacquire the lock. If using notify_all, then multiple threads can reacquire the same lock. What will happen then? And whether will a thread acquire the lock before checking the condition (i.e., lock_!=NO_LOCK && lock_!=READ_LOCK)?
  2. 在释放锁时我是否应该使用notify_all?根据该文档,一旦线程得到通知,它将重新获取锁。如果使用notify_all,则多个线程可以重新获取相同的锁。那会发生什么?并且在检查条件之前是否线程获取锁(即,锁_!= NO_LOCK && lock _!= READ_LOCK)?

Yes, you should use notify_all when releasing the lock. All condition_ waiting for the mutex_ will be waked one by one for they must lock the mutex_ firstly(this is done inner the condition_ wait operation).

是的,你应该在释放锁时使用notify_all。所有等待mutex_的condition_将被逐个唤醒,因为它们必须首先锁定mutex_(这是在condition_ wait操作内部完成的)。

  1. how can I optimize the program? obviously, when releasing a read lock, we only need to notify the threads that attempt to acquire the write lock, since read never blocks read. So how to implement this idea?
  2. 我该如何优化程序?显然,当释放读锁时,我们只需要通知尝试获取写锁的线程,因为read永远不会阻塞读。那么如何实现这个想法呢?

All threads waiting for mutex_ must be notified, for some writing threads may waiting for the read lock to be released.

必须通知所有等待mutex_的线程,因为某些写入线程可能正在等待释放读锁定。

I hope this will help you!

我希望这能帮到您!

#2


If using notify_all, then multiple threads can reacquire the same lock.

如果使用notify_all,则多个线程可以重新获取相同的锁。

No. Every notified thread will compete for lock acquirision, in the same way as mutex_.lock(). Even with notify_all, at most one thread can execute critical section's code at the time. So, using notify_all is perfectly correct.

不会。每个通知的线程都会以与mutex_.lock()相同的方式竞争锁定获取。即使使用notify_all,最多只有一个线程可以执行关键部分的代码。因此,使用notify_all是完全正确的。

  1. how can I optimize the program? obviously, when releasing a read lock, we only need to notify the threads that attempt to acquire the write lock, since read never blocks read. So how to implement this idea?
  2. 我该如何优化程序?显然,当释放读锁时,我们只需要通知尝试获取写锁的线程,因为read永远不会阻塞读。那么如何实现这个想法呢?

As read never blocks read, no read thread can wait() other read thread. So even with your current code ReleaseReadLock() can only notify write threads.

由于read永远不会阻塞读取,因此没有读取线程可以wait()其他读取线程。因此,即使使用当前代码,ReleaseReadLock()也只能通知写入线程。

Because of that, in ReleaseReadLock() you may safely use notify() instead of notify_all: no reason to awake all write threads, as only one of them can aqcuire your r/w lock.

因此,在ReleaseReadLock()中,您可以安全地使用notify()而不是notify_all:没有理由唤醒所有写入线程,因为只有其中一个可以获得您的r / w锁定。

As for other optimizations, you should better to fix artefacts, listed in this answer: https://*.com/a/12657243/3440745

至于其他优化,你应该更好地修复这个答案中列出的人工制品:https://*.com/a/12657243/3440745