**已解决:在我的类的构造函数中,我有一个Semaphore的构造赛车,它的线程构造是在其中我首先创建Semaphore,然后是Thread的第二个构造。为我工作的解决方案是首先在基类中创建Semaphore,这样我可以在派生类中依赖它。 **为什么这个代码在valgrind(helgrind)下失败?
我有一个相当小的pthreads C++程序,它在正常情况下工作正常。但是,在程序中使用valgrind的线程错误检查工具时,它似乎会发现竞争状态。这种竞争条件特别难以避免的是它发生在“Semaphore”类(它实际上只是封装了sem_init,sem_wait和sem_post)内,所以我不能用另一个Semaphore来解决这个问题(并且不应该)。我不认为valgrind会给出误报,因为我的程序在valgrind下运行时显示不同的行为。
这里的Semaphore.cpp *:
#include "Semaphore.h" #include <stdexcept> #include <errno.h> #include <iostream> Semaphore::Semaphore(bool pshared,int initial) : m_Sem(new sem_t()) { if(m_Sem==0) throw std::runtime_error("Semaphore constructor error: m_Sem == 0"); if(sem_init(m_Sem,(pshared?1:0),initial)==-1) throw std::runtime_error("sem_init failed"); } Semaphore::~Semaphore() { sem_destroy(m_Sem); delete m_Sem; } void Semaphore::lock() { if(m_Sem==0) throw std::runtime_error("Semaphore::lock error: m_Sem == 0"); int rc; for(;;){ rc = sem_wait(m_Sem); if(rc==0) break; if(errno==EINTR) continue; throw std::runtime_error("sem_wait failed"); } } void Semaphore::unlock() { if(sem_post(m_Sem)!=0) throw std::runtime_error("sem_post failed"); }
- 注意信号灯的构造如何创建一个名为“m_Sem”新sem_t,并在m_Sem还是等于0。这只是极,情况不太可能发生抛出异常意味着这个构造函数不应该允许m_Sem等于0.好吧...继续到Semaphore :: lock:无论从哪个线程调用此函数(以及构造函数),它都应该 - 理论上 - 对于m_Sem是不可能的,对吧?那么,当我在helgrind下运行我的程序时,Semaphore :: lock肯定会导致抛出这个异常“Semaphore :: lock error:m_Sem == 0”,我真的认为这应该是不可能的。
我在其他程序中使用这个Semaphore类,通过helgrind没有问题,我真的不知道我在这里做什么特别是造成这个问题。根据helgrind的说法,竞赛发生在一个线程的Semaphore构造函数写入和另一个线程的Semaphore :: lock读取之间。说实话,我什至不知道这是怎么可能的:一个对象的方法如何与该对象的构造函数有竞争条件? C++没有保证在可以调用对象的方法之前调用构造函数?即使在多线程的环境中,这又怎么会被违反呢?
无论如何,现在为valgrind输出。我正在使用valgind版本“Valgrind-3.6.0.SVN-Debian”。 Memcheck说一切都很好。下面是helgrind结果:
$ valgrind --tool=helgrind --read-var-info=yes ./try ==7776== Helgrind, a thread error detector ==7776== Copyright (C) 2007-2009, and GNU GPL'd, by OpenWorks LLP et al. ==7776== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info ==7776== Command: ./try ==7776== terminate called after throwing an instance of '==7776== Thread #1 is the program's root thread ==7776== ==7776== Thread #2 was created ==7776== at 0x425FA38: clone (clone.S:111) ==7776== by 0x40430EA: [email protected]@GLIBC_2.1 (createthread.c:249) ==7776== by 0x402950C: pthread_create_WRK (hg_intercepts.c:230) ==7776== by 0x40295A0: [email protected]* (hg_intercepts.c:257) ==7776== by 0x804CD91: Thread::Thread(void* (*)(void*), void*) (Thread.cpp:10) ==7776== by 0x804B2D5: ActionQueue::ActionQueue() (ActionQueue.h:40) ==7776== by 0x80497CA: main (try.cpp:9) ==7776== ==7776== Possible data race during write of size 4 at 0x42ee04c by thread #1 ==7776== at 0x804D9C5: Semaphore::Semaphore(bool, int) (Semaphore.cpp:8) ==7776== by 0x804B333: ActionQueue::ActionQueue() (ActionQueue.h:40) ==7776== by 0x80497CA: main (try.cpp:9) ==7776== This conflicts with a previous read of size 4 by thread #2 ==7776== at 0x804D75B: Semaphore::lock() (Semaphore.cpp:26) ==7776== by 0x804B3BE: Lock::Lock(Semaphore&) (Lock.h:17) ==7776== by 0x804B497: ActionQueue::ActionQueueLoop() (ActionQueue.h:56) ==7776== by 0x8049ED5: void* CallMemFun, &(ActionQueue::ActionQueueLoop())>(void*) (CallMemFun.h:7) ==7776== by 0x402961F: mythread_wrapper (hg_intercepts.c:202) ==7776== by 0x404296D: start_thread (pthread_create.c:300) ==7776== by 0x425FA4D: clone (clone.S:130) ==7776== std::runtime_error' what(): Semaphore::lock error: m_Sem == 0 ==7776== ==7776== For counts of detected and suppressed errors, rerun with: -v ==7776== Use --history-level=approx or =none to gain increased speed, at ==7776== the cost of reduced accuracy of conflicting-access information ==7776== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 5 from 5)
任何人使用Git和的valgrind可以从我的混帐回购分支检查出的代码(其中,备案,目前正在对提交262369c2d25eb17a0147)如下重现此:
$ git clone git://github.com/notfed/concqueue -b semaphores $ cd concqueue $ make $ valgrind --tool=helgrind --read-var-info=yes ./try