c++ - 使用信号量的读写器偏好

标签 c++ multithreading posix readerwriterlock

我目前正在研究读写器问题的正确实现(请参阅 here)。

我找到了 this Qt 码头中的解决方案通过使用信号量和互斥量保证公平对待 Reader 和 Writer 线程。基本代码是这样的:

sem_t semaphore_;
pthread_mutex_t lock_;

void PalindromeDatabase::initializeLocks()
{
    sem_init(&semaphore_, 0, NumberOfReaders_);
    pthread_mutex_init(&lock_, nullptr);
}

void PalindromeDatabase::lockReaders()
{
    sem_wait(&semaphore_);
}

void PalindromeDatabase::unlockReaders()
{
    sem_post(&semaphore_);
}

void PalindromeDatabase::lockWriters()
{
    pthread_mutex_lock(&lock_);
    {
        for (int i = 0; i < NumberOfReaders_; ++i)
            sem_wait(&semaphore_);
    }
    pthread_mutex_unlock(&lock_);
}

void PalindromeDatabase::unlockWriters()
{
    for (int i = 0; i < NumberOfReaders_; ++i)
        sem_post(&semaphore_);
}

这似乎是一个非常优雅的解决方案。与 this 中详述的 pthread_rwlock_* 行为相比,它似乎更容易、更有效。所以回答。

我想知道下面这段代码是否是对 Qt 解决方案的正确调整以更喜欢阅读器线程。

int readersActive_;
sem_t semaphore_;
pthread_mutex_t lock_;
pthread_mutex_t readLock_;
pthread_cond_t wait_;

void PalindromeDatabase::initializeLocks()
{
    sem_init(&semaphore_, 0, numberOfReaders_);
    pthread_mutex_init(&lock_, nullptr);
    pthread_mutex_init(&readLock_, nullptr);
    pthread_cond_init(&wait_, nullptr);
}

void PalindromeDatabase::lockReaders()
{
    pthread_mutex_lock(&lock_);
    {
        pthread_mutex_lock(&readLock_);
        sem_wait(&semaphore_);
        pthread_mutex_unlock(&readLock_);

        ++readersActive_;
    }
    pthread_mutex_unlock(&lock_);
}

void PalindromeDatabase::lockReaders()
{
    pthread_mutex_lock(&lock_);
    {
        pthread_mutex_lock(&readLock_);
        sem_wait(&semaphore_);
        pthread_mutex_unlock(&readLock_);

        ++readersActive_;
    }
    pthread_mutex_unlock(&lock_);
}

void PalindromeDatabase::unlockReaders()
{
    sem_post(&semaphore_);

    pthread_mutex_lock(&lock_);
    {
        --readersActive_;

        if (readersActive_ == 0)
            pthread_cond_signal(&wait_);
    }
    pthread_mutex_unlock(&lock_);
}

void PalindromeDatabase::lockWriters()
{
    pthread_mutex_lock(&lock_);
    {
        if (readersActive_ != 0)
        {
            do
            {
                pthread_cond_wait(&wait_, &lock_);
            } while (readersActive_ != 0);
        }

        pthread_mutex_lock(&readLock_);
        for (int i = 0; i < numberOfReaders_; ++i)
            sem_wait(&semaphore_);
        pthread_mutex_unlock(&readLock_);
    }
    pthread_mutex_unlock(&lock_);
}

void PalindromeDatabase::unlockWriters()
{
    for (int i = 0; i < numberOfReaders_; ++i)
        sem_post(&semaphore_);
}

最佳答案

你的代码有很多问题:

  1. 信号量仅供作者使用,因此没有意义。
  2. 在为 writer 锁定时,您使用互斥锁,而在解锁时则不用。
  3. 当#readers 变为零时,readers 发出条件变化的信号,writer 等待条件变量的信号,但不检查条件。
  4. 在为 writer 锁定时,如果 #readers 已经为零,它实际上不会锁定。

考虑到我所说的这很容易,锁定仍然很棘手,我想了想,我希望我用这个伪代码破解它,关注正确的顺序而不是正确的符号:

void lockReader()
{
  lock(rdmutex);  // make sure Reader and Writer can't interfere during locking
  lock(wrmutex);  // lock mutex so waitfor can unlock
  while (writer_)
    waitfor(wrcv, wrmutex);  // no active writers

  ++readers_; // at least 1 reader present
  unlock(wrmutex);
  unlock(rdmutex);
}

void unlockReader()
{
  lock(rdmutex);
  bool noReaders = (--readers_ == 0);
  unlock(rdmutex);
  if (noReaders) signal(rdcv); // signal when no more readers
}

void lockWriter()
{
  lock(WritersLock);  // only 1 writer allowed
  lock(rdmutex);  // lock mutex so waitfor can unlock and no interference by lockReader
  while (readers_ != 0)
    waitfor(rdcv, rdmutex);  // wait until no more readers
  lock(wrmutex);
  writer_ = true;  // a writer is busy
  unlock(wrmutex);
  unlock(rdmutex);
  // WritersLock is still locked
}

void unlockWriter()
{
  lock(wrmutex);
  writer_ = false;
  unlock(wrmutex);
  signal(wrcv);  // no more writer (until WritersLock is unlocked)

  unlock(WritersLock);
}

事实证明,Qt 实现更简单,但我的算法不需要提前知道最大读者数。

关于c++ - 使用信号量的读写器偏好,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8587786/

相关文章:

ios - Objective-c 验证当前执行线程,以防万一,在正确的线程中重新执行该方法

macos - 在命名管道(FIFO)上使用 poll() 时,OS X 看起来真的有一个错误......专家可以确认吗?

c++ - pthread_create 没有参数?

c# - 如果抛出异常,使 extern C++ 函数返回一条消息

c++ - 如何将位序列放入字节(C/C++)

c++ - 在 main() 与全局定义外部变量

regex - 无法使用 nginx logwarn 正确解析包含特定关键字的日志行

c++ - 推导模板参数继续

multithreading - 在 OpenMP 'for' 中使用 rand_r 使用 2 个线程时速度较慢

c++ - 如何在堆上初始化线程? (使用 “new”关键字)