我有一个多线程应用程序,它创建了 48 个线程,这些线程都需要访问一个公共属性(stl::map)。只有在线程启动时才会写入映射,其余时间将从中读取映射。这似乎是 pthread_rw_lock 的完美用例,而且一切似乎都运行良好。
我遇到了一个完全不相关的段错误并开始分析核心。使用 gdb,我执行了命令info threads
并对结果感到非常惊讶。我观察到几个线程实际上正在按预期从映射中读取,但奇怪的是几个线程在等待 rw_lock 的 pthread_rwlock_rdlock() 中被阻塞。
这是等待锁的线程的堆栈跟踪:
#0 0xffffe430 in __kernel_vsyscall ()
#1 0xf76fe159 in __lll_lock_wait () from /lib/libpthread.so.0
#2 0xf76fab5d in pthread_rwlock_rdlock () from /lib/libpthread.so.0
#3 0x0804a81a in DiameterServiceSingleton::getDiameterService(void*) ()
有这么多线程,很难说有多少正在读取,有多少被阻塞,但我不明白为什么任何线程会被阻塞等待读取,考虑到其他线程已经在读取。
所以这是我的问题:为什么有些线程被阻塞等待读取 rw_lock,而其他线程已经在读取它?似乎可以同时读取的线程数是有限制的。
我查看了pthread_rwlock_attr_t
功能,没有看到任何相关内容。
操作系统是 Linux,SUSE 11。
以下是相关代码:
{
pthread_rwlock_init(&serviceMapRwLock_, NULL);
}
// This method is called for each request processed by the threads
Service *ServiceSingleton::getService(void *serviceId)
{
pthread_rwlock_rdlock(&serviceMapRwLock_);
ServiceMapType::const_iterator iter = serviceMap_.find(serviceId);
bool notFound(iter == serviceMap_.end());
pthread_rwlock_unlock(&serviceMapRwLock_);
if(notFound)
{
return NULL;
}
return iter->second;
}
// This method is only called when the app is starting
void ServiceSingleton::addService(void *serviceId, Service *service)
{
pthread_rwlock_wrlock(&serviceMapRwLock_);
serviceMap_[serviceId] = service;
pthread_rwlock_unlock(&serviceMapRwLock_);
}
更新:
正如 MarkB 在评论中提到的,如果我将 pthread_rwlockattr_getkind_np() 设置为优先考虑写入器,并且有写入器阻塞等待,那么观察到的行为将是有意义的。但是,我使用我认为优先考虑读者的默认值。我刚刚验证没有线程阻塞等待写入。我还按照@Shahbaz 在评论中的建议更新了代码并获得了相同的结果。