c – pthread_rwlock可以同时读取多少个读者?

前端之家收集整理的这篇文章主要介绍了c – pthread_rwlock可以同时读取多少个读者?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个多线程应用程序,它创建了48个线程,所有这些线程都需要访问公共属性(stl :: map).地图将仅在线程开始时写入,其余时间将从中读取地图.这似乎是pthread_rw_lock的完美用例,并且似乎都运行良好.

我碰到了一个完全不相关的seg-fault并开始分析核心.使用gdb,我执行了命令信息线程,并对结果感到非常惊讶.我观察到几个线程实际上是按照预期从地图中读取的,但奇怪的是,在pthread_rwlock_rdlock()中等待rw_lock的几个线程被阻塞了.

以下是等待锁定的线程的堆栈跟踪:

  1. #0 0xffffe430 in __kernel_vsyscall ()
  2. #1 0xf76fe159 in __lll_lock_wait () from /lib/libpthread.so.0
  3. #2 0xf76fab5d in pthread_rwlock_rdlock () from /lib/libpthread.so.0
  4. #3 0x0804a81a in DiameterServiceSingleton::getDiameterService(void*) ()

有这么多线程,很难说有多少是在阅读,有多少是被阻止的,但我不明白为什么任何线程都会被阻塞等待阅读,考虑到其他线程已经在阅读.

所以这是我的问题:当其他线程已经从中读取时,为什么有些线程被阻塞等待读取rw_lock?似乎可以同时读取的线程数有限制.

我看过pthread_rwlock_attr_t函数并没有看到任何相关的东西.

操作系统是Linux,SUSE 11.

这是相关的代码

  1. {
  2. pthread_rwlock_init(&serviceMapRwLock_,NULL);
  3. }
  4.  
  5. // This method is called for each request processed by the threads
  6. Service *ServiceSingleton::getService(void *serviceId)
  7. {
  8. pthread_rwlock_rdlock(&serviceMapRwLock_);
  9. ServiceMapType::const_iterator iter = serviceMap_.find(serviceId);
  10. bool notFound(iter == serviceMap_.end());
  11. pthread_rwlock_unlock(&serviceMapRwLock_);
  12.  
  13. if(notFound)
  14. {
  15. return NULL;
  16. }
  17.  
  18. return iter->second;
  19. }
  20.  
  21. // This method is only called when the app is starting
  22. void ServiceSingleton::addService(void *serviceId,Service *service)
  23. {
  24. pthread_rwlock_wrlock(&serviceMapRwLock_);
  25. serviceMap_[serviceId] = service;
  26. pthread_rwlock_unlock(&serviceMapRwLock_);
  27. }

更新:

正如MarkB的评论中所提到的,如果我设置了pthread_rwlockattr_getkind_np()来为编写器提供优先级,并且有一个写入器被阻塞等待,那么观察到的行为就有意义了.但是,我使用默认值,我认为是优先考虑读者.我刚刚确认没有线程被阻止等待写入.我还在评论中更新@Shahbaz建议的代码,并得到相同的结果.

解决方法

您只是观察了获取锁定所涉及的固有性能问题.这需要一些时间,你恰好在它的中间抓住那些线程.当受锁保护的操作持续时间非常短时尤其如此.

Edit: Reading the source,glibc uses lll_lock to protect critical sections within its own pthread library data structures. The pthread_rwlock_rdlock checks several flags and increments counters,so it does those things while holding a lock. Once those are done,the lock is released with lll_unlock.

为了演示,我实现了一个在获取rwlock后休眠的短例程.主线程等待它们完成.但在等待之前,它会打印线程实现的并发性.

  1. enum { CONC = 50 };
  2.  
  3. pthread_rwlock_t rwlock;
  4. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  5. pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  6. unsigned count;
  7.  
  8. void *routine(void *arg)
  9. {
  10. int *fds = static_cast<int *>(arg);
  11. pthread_rwlock_rdlock(&rwlock);
  12. pthread_mutex_lock(&mutex);
  13. ++count;
  14. if (count == CONC) pthread_cond_signal(&cond);
  15. pthread_mutex_unlock(&mutex);
  16. sleep(5);
  17. pthread_rwlock_unlock(&rwlock);
  18. pthread_t self = pthread_self();
  19. write(fds[1],&self,sizeof(self));
  20. return 0;
  21. }

并且主线程等待计数器达到50:

  1. int main()
  2. {
  3. int fds[2];
  4. pipe(fds);
  5. pthread_rwlock_init(&rwlock,0);
  6. pthread_mutex_lock(&mutex);
  7. for (int i = 0; i < CONC; i++) {
  8. pthread_t tid;
  9. pthread_create(&tid,NULL,routine,fds);
  10. }
  11. while (count < CONC) pthread_cond_wait(&cond,&mutex);
  12. pthread_mutex_unlock(&mutex);
  13. std::cout << "count: " << count << std::endl;
  14. for (int i = 0; i < CONC; i++) {
  15. pthread_t tid;
  16. read(fds[0],&tid,sizeof(tid));
  17. pthread_join(tid,0);
  18. }
  19. pthread_rwlock_destroy(&rwlock);
  20. pthread_exit(0);
  21. }

编辑:使用C 11线程支持简化示例:

  1. enum { CONC = 1000 };
  2. std::vector<std::thread> threads;
  3.  
  4. pthread_rwlock_t rwlock;
  5. std::mutex mutex;
  6. std::condition_variable cond;
  7. unsigned count;
  8.  
  9. void *routine(int self)
  10. {
  11. pthread_rwlock_rdlock(&rwlock);
  12. { std::unique_lock<std::mutex> lk(mutex);
  13. if (++count == CONC) cond.notify_one(); }
  14. sleep(5);
  15. pthread_rwlock_unlock(&rwlock);
  16. return 0;
  17. }
  18.  
  19. int main()
  20. {
  21. pthread_rwlock_init(&rwlock,0);
  22. { std::unique_lock<std::mutex> lk(mutex);
  23. for (int i = 0; i < CONC; i++) {
  24. threads.push_back(std::thread(routine,i));
  25. }
  26. cond.wait(lk,[](){return count == CONC;}); }
  27. std::cout << "count: " << count << std::endl;
  28. for (int i = 0; i < CONC; i++) {
  29. threads[i].join();
  30. }
  31. pthread_rwlock_destroy(&rwlock);
  32. pthread_exit(0);
  33. }

猜你在找的C&C++相关文章