首页 > 解决方案 > 找出哪些线程拥有 pthread_rwlock_t

问题描述

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

对于常规互斥锁,是否可以确定持有互斥锁的线程?但是如何为 ar/w 锁做到这一点?

标签: multithreading

解决方案


您的好问题有一些完整答案的问题:

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

假设您可以解开上面的特定配置,我们正在查看两种不同的结果:有一个writer或一组当前导致 pthread_rw_lock() 阻塞某些调用者的reader 。相反,互斥锁只有一个所有者,并且只有该所有者才能释放它。

因此,确定您的系统是否具有可找到的所有者集的第一个测试是查看它是否确实记录了所有权。对此的一种快速破解方法是让一个线程获取 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。


推荐阅读