【问题标题】:reader/writer lock in pthreadpthread中的读/写锁
【发布时间】:2013-10-20 20:44:20
【问题描述】:

我正在学习 pthread,遇到了读写器锁。场景非常简单;一个由所有线程共享的全局变量,读取器不断打印同一个全局变量的当前值,而写入器将更新同一个变量。我可以通过使用两个互斥锁(pthread_mutex_t)来实现这种同步,但我想使用“一个”读写器锁来实现同样的结果。但是,使用一个读写器锁,如此处所示(程序的输出,如下),读取器只能看到 x 的第一个值,而看不到对全局变量的任何更新。请给这里一些亮点。

代码:

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include <poll.h>

#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))

int x = 0;

pthread_rwlock_t lock_rw = PTHREAD_RWLOCK_INITIALIZER;

void *reader_thread(void *arg)
{
    int i;
    int newx, oldx;
    newx = oldx = -1;

    pthread_rwlock_t *p = (pthread_rwlock_t *)arg;

    if (pthread_rwlock_rdlock(p) != 0) {
        perror("reader_thread: pthread_rwlock_rdlock error");
        exit(__LINE__);
    }

    for (i = 0; i < 100; i++) {
        newx = ACCESS_ONCE(x);
        if (newx != oldx) {
            printf("reader_lock: x: %d\n",x);
        }
        oldx = newx;
        poll(NULL, 0, 1);
    }

    if (pthread_rwlock_unlock(p) != 0) {
        perror("reader thread: pthred_rwlock_unlock error");
        exit(__LINE__);
    }

    return NULL;
}

void *writer_thread(void *arg)
{
    int i;
    pthread_rwlock_t *p = (pthread_rwlock_t *)arg;

    if (pthread_rwlock_wrlock(p) != 0) {
        perror("writer thread: pthread_rwlock_wrlock error");
        exit(__LINE__);
    }

    for (i = 0; i < 3; i++) {
        ACCESS_ONCE(x)++;
        poll(NULL, 0, 5);
    }

    if (pthread_rwlock_unlock(p) != 0) {
        perror("writer thread: pthread_rwlock_unlock error");
        exit(__LINE__);
    }

    return NULL;
}

int main(void)
{
    pthread_t tid1, tid2;
    void *vp;
    if (pthread_create(&tid1, NULL, reader_thread, &lock_rw) != 0) {
        perror("pthread_create error");
        exit (__LINE__);
    }

    if (pthread_create(&tid2, NULL, writer_thread, &lock_rw) != 0) {
        perror("pthread_create error");
        exit (__LINE__);
    }

    //wait for the thread to complete
    if (pthread_join(tid1, &vp) != 0) {
        perror("pthread_join error");
        exit (__LINE__);
    }

    if (pthread_join(tid2, &vp) != 0) {
        perror("pthread_join error");
        exit (__LINE__);
    }

    printf("Parent process sees x: %d\n",x);
    return 0;
}

gcc pthread_rwlock.c -o rwlock -pthread -Wall -Werror

./rwlock

reader_lock: x: 0

父进程看到 x: 3

【问题讨论】:

  • 关于我的系统的一些信息,我的系统是 64 位的,在 64 位 Linux v3.11.2 上运行
  • 为什么需要两个互斥锁来实现同步?我错过了什么吗?

标签: c multithreading pthreads


【解决方案1】:

当一个线程获取锁时,其他试图获取相同锁的线程将被挂起,直到第一个线程释放锁。

这里发生的是您的阅读器线程启动,获取锁,并进入for/poll 循环。

写入线程启动,尝试获取读取线程已占用的锁,并在pthread_rwlock_wrlock 上保持阻塞。

您真正想要做的是将您的lock/unlock 放在您访问共享变量的代码之前和之后。

thread_rwlock_rdlock(p);
newx = ACCESS_ONCE(x);
thread_rwlock_unlock(p);
...
thread_rwlock_wrlock(p);
ACCESS_ONCE(x)++;
thread_rwlock_unlock(p);

【讨论】:

  • 这和只使用互斥锁(pthread_mutex_t)不一样吗?在我的设置中,我尝试使用互斥锁而不是读写器锁,并将这些调用从 pthread_rwlock_{rd|wr}lock 替换为 pthread_mutex_lock() 并将它们放置在这些热点周围,并实现了我想要的(读者可以看到所有中间x) 的值,但是,这种方法对我来说看起来不正确。读写锁应该带来一些额外的功能,不是吗?
  • @kumar,rwlock 并没有在标准互斥锁上引入任何额外的安全保证。但是,它可能会减少高读取器争用的问题(但不一定,因为它更复杂并且锁定它更慢)。
  • 来自 pthread_rwlock_wrlock 的手册页,“如果没有其他线程(读取器或写入器)持有读写锁 rwlock,则调用线程将获取写入锁。否则,线程应阻塞 直到它可以获取锁”。所以我假设作家不会被阻止,但事实并非如此。我想我需要更多地探索读写器锁才能完全理解用例。谢谢@zch。现在,我会接受 Flavio 的建议。
  • 正如@zch 所说,只有当您有许多读取器线程访问相同的值时,读/写锁才会有所作为。如果您只有一个读取器,则读/写锁的行为方式与标准互斥锁相同。
  • @kumar:读写锁的目的是让许多读者同时持有读锁,但仍然给写者独占访问权限。使用普通互斥锁,所有线程都将拥有独占访问权限。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-06
  • 2023-03-23
  • 2023-02-20
  • 2011-01-25
  • 2011-12-04
相关资源
最近更新 更多