【问题标题】:helgrind in valgrind complains with simple mutexvalgrind 中的 helgrind 抱怨简单的互斥锁
【发布时间】:2015-08-12 12:21:50
【问题描述】:

我正在调试一些线程代码,并且正在使用 valgrind --tool=helgrind 并且由于某种原因 helgrind 不喜欢下面的简单示例。

在我启动一个线程之前,我锁定了互斥锁。在线程结束时我解锁,从而确保一次只能运行一个线程,假设互斥锁将被锁定直到线程完成。

为什么根据 valgrind 无效?

这是一个更大程序的一部分,我的主程序正在读取/解析数据,它将启动一个分析线程,但我只希望一次运行一个分析线程。

#include <pthread.h>
#include <stdio.h>

pthread_mutex_t mutex;

void *inner(void *ptr){
  size_t threadid=(size_t)ptr;
  int sleepval = lrand48() % 5 +1;
  fprintf(stderr,"thread: %lu will wait:%d\n",threadid,sleepval);fflush(stderr);  
  sleep(sleepval);
  pthread_mutex_unlock(&mutex);
}




int outer(size_t ntimes){
  pthread_t thread1;
  size_t i;
  for(i=0;i<ntimes;i++){
    pthread_mutex_lock(&mutex);
    if(pthread_create( &thread1, NULL, inner, (void*) i))
      fprintf(stderr,"Problems creating thread\n");
  }
    pthread_mutex_lock(&mutex);
    pthread_mutex_unlock(&mutex);
}


int main(){
  pthread_mutex_init(&mutex, NULL);
  outer(3);
  return 0;
}

==8326== Helgrind, a thread error detector
==8326== Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.
==8326== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==8326== Command: ./a.out
==8326== 
thread: 0 will wait:1
==8326== ---Thread-Announcement------------------------------------------
==8326== 
==8326== Thread #1 is the program's root thread
==8326== 
==8326== ----------------------------------------------------------------
==8326== 
==8326== Thread #1: Attempt to re-lock a non-recursive lock I already hold
==8326==    at 0x4C32010: pthread_mutex_lock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x400959: outer (threadTest.c:21)
==8326==    by 0x4009DA: main (threadTest.c:32)
==8326==  Lock was previously acquired
==8326==    at 0x4C32145: pthread_mutex_lock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x400959: outer (threadTest.c:21)
==8326==    by 0x4009DA: main (threadTest.c:32)
==8326== 
==8326== ---Thread-Announcement------------------------------------------
==8326== 
==8326== Thread #2 was created
==8326==    at 0x515543E: clone (clone.S:74)
==8326==    by 0x4E44199: do_clone.constprop.3 (createthread.c:75)
==8326==    by 0x4E458BA: pthread_create@@GLIBC_2.2.5 (createthread.c:245)
==8326==    by 0x4C30C90: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x400976: outer (threadTest.c:22)
==8326==    by 0x4009DA: main (threadTest.c:32)
==8326== 
==8326== ----------------------------------------------------------------
==8326== 
==8326== Thread #2 unlocked lock at 0x6010A0 currently held by thread #1
==8326==    at 0x4C325C0: pthread_mutex_unlock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x400937: inner (threadTest.c:11)
==8326==    by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x4E45181: start_thread (pthread_create.c:312)
==8326==    by 0x515547C: clone (clone.S:111)
==8326==   Lock at 0x6010A0 was first observed
==8326==    at 0x4C31DDA: pthread_mutex_init (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x4009D0: main (threadTest.c:31)
==8326== 
==8326== ----------------------------------------------------------------
==8326== 
==8326== Thread #1: Bug in libpthread: recursive write lock granted on mutex/wrlock which does not support recursion
==8326==    at 0x4C32145: pthread_mutex_lock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x400959: outer (threadTest.c:21)
==8326==    by 0x4009DA: main (threadTest.c:32)
==8326== 
thread: 1 will wait:4
==8326== ---Thread-Announcement------------------------------------------
==8326== 
==8326== Thread #3 was created
==8326==    at 0x515543E: clone (clone.S:74)
==8326==    by 0x4E44199: do_clone.constprop.3 (createthread.c:75)
==8326==    by 0x4E458BA: pthread_create@@GLIBC_2.2.5 (createthread.c:245)
==8326==    by 0x4C30C90: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x400976: outer (threadTest.c:22)
==8326==    by 0x4009DA: main (threadTest.c:32)
==8326== 
==8326== ----------------------------------------------------------------
==8326== 
==8326== Thread #3 unlocked lock at 0x6010A0 currently held by thread #1
==8326==    at 0x4C325C0: pthread_mutex_unlock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x400937: inner (threadTest.c:11)
==8326==    by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x4E45181: start_thread (pthread_create.c:312)
==8326==    by 0x515547C: clone (clone.S:111)
==8326==   Lock at 0x6010A0 was first observed
==8326==    at 0x4C31DDA: pthread_mutex_init (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x4009D0: main (threadTest.c:31)
==8326== 
thread: 2 will wait:1
==8326== ----------------------------------------------------------------
==8326== 
==8326== Thread #1: Attempt to re-lock a non-recursive lock I already hold
==8326==    at 0x4C32010: pthread_mutex_lock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x4009B1: outer (threadTest.c:25)
==8326==    by 0x4009DA: main (threadTest.c:32)
==8326==  Lock was previously acquired
==8326==    at 0x4C32145: pthread_mutex_lock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x400959: outer (threadTest.c:21)
==8326==    by 0x4009DA: main (threadTest.c:32)
==8326== 
==8326== ---Thread-Announcement------------------------------------------
==8326== 
==8326== Thread #4 was created
==8326==    at 0x515543E: clone (clone.S:74)
==8326==    by 0x4E44199: do_clone.constprop.3 (createthread.c:75)
==8326==    by 0x4E458BA: pthread_create@@GLIBC_2.2.5 (createthread.c:245)
==8326==    by 0x4C30C90: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x400976: outer (threadTest.c:22)
==8326==    by 0x4009DA: main (threadTest.c:32)
==8326== 
==8326== ----------------------------------------------------------------
==8326== 
==8326== Thread #4 unlocked lock at 0x6010A0 currently held by thread #1
==8326==    at 0x4C325C0: pthread_mutex_unlock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x400937: inner (threadTest.c:11)
==8326==    by 0x4C30E26: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x4E45181: start_thread (pthread_create.c:312)
==8326==    by 0x515547C: clone (clone.S:111)
==8326==   Lock at 0x6010A0 was first observed
==8326==    at 0x4C31DDA: pthread_mutex_init (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x4009D0: main (threadTest.c:31)
==8326== 
==8326== ----------------------------------------------------------------
==8326== 
==8326== Thread #1: Bug in libpthread: recursive write lock granted on mutex/wrlock which does not support recursion
==8326==    at 0x4C32145: pthread_mutex_lock (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==8326==    by 0x4009B1: outer (threadTest.c:25)
==8326==    by 0x4009DA: main (threadTest.c:32)
==8326== 
==8326== 
==8326== For counts of detected and suppressed errors, rerun with: -v
==8326== Use --history-level=approx or =none to gain increased speed, at
==8326== the cost of reduced accuracy of conflicting-access information
==8326== ERROR SUMMARY: 9 errors from 7 contexts (suppressed: 104 from 61)

【问题讨论】:

  • 1.在outer 中锁定并直接解锁mutex。 2、mutex只锁定在inner,不能解锁outer

标签: c++ c pthreads mutex


【解决方案1】:

直接的问题是您将一个互斥锁锁定在一个线程中并在另一个线程中解锁它。您还尝试在同一线程中两次锁定相同的非递归互斥锁。因为只有获得锁的线程才能释放它,这将是一个死锁。

要实现您可能想要的 senantic,您只需加入新创建的线程:加入将阻塞,直到相应的线程退出。

或者,您可以保护活动线程计数,该计数由创建线程增加并在线程完成时减少。结束线程也会发出一个条件变量的信号。创建线程将检查计数并在计数过高时等待条件变量。

拥有一个使用并可能阻塞作业队列的处理器线程可能是限制工作线程数量的最简单和最有效的方法。

【讨论】:

    【解决方案2】:

    来自pthread_mutex_lock的手册页:

    如果一个线程试图解锁一个它尚未锁定的互斥锁或一个 未锁定的互斥体,未定义的行为结果。

    因此您必须在同一个线程中锁定和解锁互斥锁。

    您的函数还应该返回一个与原型匹配的值。

    #include <pthread.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    pthread_mutex_t mutex;
    
    void *inner(void *ptr){
      size_t threadid = *(size_t *)ptr;
      int sleepval = rand() % 5 +1;
      pthread_mutex_lock(&mutex);
      fprintf(stderr,"thread: %lu will wait:%d\n",threadid,sleepval);
      fflush(stderr);
      sleep(sleepval);
      pthread_mutex_unlock(&mutex);
      return NULL;
    }
    
    int outer(size_t ntimes){
      pthread_t thread[ntimes];
      size_t i, id[ntimes];
      for(i=0;i<ntimes;i++){
        id[i] = i;
        if(pthread_create(thread + i, NULL, inner, &id[i]))
          fprintf(stderr,"Problems creating thread\n");
      }
    
      for(i=0;i<ntimes;i++)
        pthread_join(thread[i], NULL);
      return 0;
    }
    
    int main(void){
    
      pthread_mutex_init(&mutex, NULL);
      outer(3);
      return 0;
    }
    

    这对我有用。我还添加了缺少的标头并更改了函数参数以匹配新要求。

    附注:outer 函数现在使用可变长度数组,因此它只能在 C99 中工作,而不是在 C++ 中(问题被标记为两者)。

    【讨论】:

      猜你喜欢
      • 2012-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-14
      • 1970-01-01
      • 2018-05-23
      相关资源
      最近更新 更多