【问题标题】:Finding out which threads own a pthread_rwlock_t找出哪些线程拥有 pthread_rwlock_t
【发布时间】:2020-12-07 13:50:40
【问题描述】:

我如何(在 linux 上)查看哪些线程拥有 pthread_rwlock_t(或 std::shared_mutex)?

对于常规互斥锁,有 Is it possible to determine the thread holding a mutex?,但如何为 r/w 锁执行此操作?

【问题讨论】:

    标签: multithreading


    【解决方案1】:

    你的好问题有几个问题没有完整的答案:

    1. 这取决于您运行的操作系统内核,甚至可能取决于哪个版本。
    2. 这取决于您使用的是哪个 libc/libpthread,甚至可能取决于哪个编译器。

    假设您可以解开上面的特定配置,我们正在查看两种不同的结果:当前导致 pthread_rw_lock( ) 阻止某些来电者。 相比之下,互斥锁只有一个 owner 并且只有那个 owner 可以释放它。

    因此,确定您的系统是否具有可找到的所有者集的第一个测试是查看它是否确实记录了所有权。对此的快速破解是让一个线程获取 rwlock 以进行读取或写入,然后向第二个发出信号以释放它。如果发布失败,你的实现会正确记录它,你就有机会;如果没有,您的实现可能会使用 mutex + condvar + counter 实现 rwlock;所以它不知道所有权。

    所以,一些代码:

    #include <stdio.h>
    #include <pthread.h>
    
    pthread_mutex_t lock;
    pthread_cond_t cv;
    pthread_rwlock_t rwl;
    int ready;
    
    void *rlse(void *_)
    {
        int *t = _;
        pthread_mutex_lock(&lock);
        while (ready == 0) {
            pthread_cond_wait(&cv, &lock);
        }
        ready = 0;
        pthread_cond_signal(&cv);
        pthread_mutex_unlock(&lock);
        *t = pthread_rwlock_unlock(&rwl);
        return 0;
    }
    
    void *get(void *_)
    {
        int *t = _;
        *t = (*t) ? pthread_rwlock_wrlock(&rwl) : pthread_rwlock_rdlock(&rwl);
        if (*t == 0) {
            pthread_mutex_lock(&lock);
            ready = 1;
            pthread_cond_signal(&cv);
            while (ready == 1) {
                pthread_cond_wait(&cv, &lock);
            }
            pthread_mutex_unlock(&lock);
        }
        return 0;
    }
    
    int main()
    {
        pthread_t acq, rel;
        int v0, v1;
        int i;
        for (i = 0; i < 2; i++) {
            pthread_rwlock_init(&rwl, 0);
            pthread_mutex_init(&lock, 0);
            pthread_cond_init(&cv, 0);
            v0 = i;
            pthread_create(&acq, 0, get, &v0);
            pthread_create(&rel, 0, rlse, &v1);
            pthread_join(acq, 0);
            pthread_join(rel, 0);
            printf("%s: %d %d\n", i ? "write" : "read", v0, v1);
        }
        return 0;
    }
    

    我们的运行方式:

    u18:src $ cc rw.c -lpthread -o rw
    u18:src $ ./rw
    read: 0 0
    write: 0 0
    

    这告诉我们,在任何一种情况下(rdlock,wrlock),与调用线程不同的线程都可以释放rwlock,因此它基本上没有所有者。

    如果发现的感觉少了一点,我们可以通过阅读 pthread_rwlock_unlock 的手册页找到一点,其中指出这种情况是未定义的行为,这是一个很好的解决办法。

    Posix 建立了一个基础,而不是一个限制,因此您的实现有可能支持这种所有权。我上面的程序是一个很好的调查工具;如果它出现类似 ENOTOWNER 的东西;但 EINVAL 将是非常不确定的。

    glic 的 rwlock 的内部结构 (sysdeps/htl/bits/types/struct___pthread_rwlock.h):

    struct __pthread_rwlock
    {
      __pthread_spinlock_t __held;
      __pthread_spinlock_t __lock;
      int __readers;
      struct __pthread *__readerqueue;
      struct __pthread *__writerqueue;
      struct __pthread_rwlockattr *__attr;
      void *__data;
    };
    

    证实了我们的怀疑;起初我对队列和所有东西抱有希望,但稍微深入研究代码后发现它们是等待列表,而不是所有者列表。

    以上是在 ubuntu 18.04 上运行的; linux 4.15.0-112-通用; gcc 7.5.0; glibc 2.27 libpthread 2.27.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-16
      • 1970-01-01
      • 2012-10-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多