|
Boost Users : |
Subject: Re: [Boost-users] boost::mutex::scoped_lock crashes on OSX
From: David Medine (dmedine_at_[hidden])
Date: 2015-12-17 17:14:09
On 12/16/2015 1:58 PM, Vicente J. Botet Escriba wrote:
> Le 16/12/2015 19:34, David Medine a écrit :
>>
>>
>> On 12/16/2015 9:41 AM, Vicente J. Botet Escriba wrote:
>>> Le 15/12/2015 20:11, David Medine a écrit :
>>>> I am using boost in a python extension and it is having some
>>>> problems on OSX. Specifically, I use a mutex of type boost::mutex
>>>> in both the constructor and destructor methods. The constructor
>>>> goes fine and the destructor crashes. The code works perfectly well
>>>> on both Windows and Linux.
>>>>
>>>> When my class is building itself, it calls functions like this one
>>>> a bunch of times:
>>>>
>>>> void enter_headers_phase(bool phase_locked) {
>>>> if (phase_locked) {
>>>> boost::mutex::scoped_lock lock(phase_mut_);
>>>> headers_to_finish_++;
>>>> }
>>>> }
>>>>
>>>> where phase_mut_ is of type boost::mutex. When debugging in XCode,
>>>> I see nice looking members for phase_mut_ at this point in the
>>>> program:
>>>>
>>>> phase_mut_ (boost::mutex)
>>>> m (pthread_mutex_t)
>>>> __sig (long) 1297437784 1297437784
>>>> __opaque char [56] ""
>>>>
>>>>
>>>> Later, when I am destroying, I make a nearly identical call as before:
>>>>
>>>> ...
>>>>
>>>> {
>>>> boost::mutex::scoped_lock lock(phase_mut_);
>>>> shutdown_ = true;
>>>> }
>>>>
>>>> ...
>>>>
>>>> but now, my phase_mut_ looks like it has an apparently empty _sig
>>>> member:
>>>>
>>>> phase_mut_ (boost::mutex)
>>>> m (pthread_mutex_t)
>>>> __sig (long)
>>>> __opaque (char [56]) ""
>>>>
>>>> When we go down the line of the mutex code in boost and finally
>>>> arrive at line 62 in boost/thread/pthread/mutex.hpp:
>>>>
>>>> ret = ::pthread_mutex_lock(m);
>>>>
>>>> I get a segmentation fault: EXC_BAD_ACCESS
>>>
>>> Hi,
>>>
>>> I need more context. Could you provide the declaration where
>>> phase_mut_ is in and the destructor of this class as well as where
>>> are you calling
>>
>> Sure. The variable boost::mutex phase_mut_ is a private member of the
>> class 'recorder' as are several functions such as the one I quoted
>> above,
>>
>> private:
>>
>> // some other private members
>> bool shutdown_;
>> boost::uint32_t headers_to_finish_;
>> boost::mutex phase_mut_;
>> std::vector<thread_p> stream_threads_;
>>
>> void enter_headers_phase(bool phase_locked) {
>> if (phase_locked) {
>> boost::mutex::scoped_lock lock(phase_mut_);
>> headers_to_finish_++;
>> }
>> }
>>
>> void leave_headers_phase(bool phase_locked) {
>> if (phase_locked) {
>> boost::mutex::scoped_lock lock(phase_mut_);
>> headers_to_finish_--;
>> lock.unlock();
>> ready_for_streaming_.notify_all();
>> }
>> }
>> // etc.
>>
>> In the constructor, a thread is spawned that calls some of these
>> functions. Here is the constructor (abbreviated):
>>
>> class recording {
>> public:
>> recording(const std::string &filename, const
>> std::vector<lsl::stream_info> &streams, const
>> std::vector<std::string> &watchfor, bool collect_offsets=true) :
>> offsets_enabled_(collect_offsets), unsorted_(false),
>> shutdown_(false), streamid_(0), streaming_to_finish_(0),
>> headers_to_finish_(0) {
>>
>> // blah blah blah
>>
>> // create a recording thread for each stream
>> for (std::size_t k=0;k<streams.size();k++)
>> stream_threads_.push_back(thread_p(newboost::thread(&recording::record_from_streaminfo,this,streams[k],true)));
>>
>> // blah blah blah
>> }
>>
>>
>> This function record_from_streaminfo then callsenter_headers_phase
>> with the boolean true as the argument:
>>
>> void record_from_streaminfo(lsl::stream_info src, bool phase_locked) {
>> // blah blah blah
>>
>> // --- headers phase
>> try {
>> enter_headers_phase(phase_locked);
>> }
>>
>> // blah blah blah
>>
>> }
>>
>> At this point the application is doing its recording and everything
>> is great.
>>
>>>
>>> {
>>> boost::mutex::scoped_lock lock(phase_mut_);
>>> shutdown_ = true;
>>> }
>>>
>>> while on the destructor?
>>
>> Here is the destructor (also abbreviated , but the mutex lock is the
>> very first thing that happens):
>>
>> ~recording() {
>> try {
>> // set the shutdown flag (from now on no more new streams)
>> {
>> boost::mutex::scoped_lock lock(phase_mut_);
>> shutdown_ = true;
>> }
>> // etc. etc.
>> }
>>
> I don't know from were the problem comes from, but you don't need to
> lock on destruction as only one thread can call to the destructor.
> However you need to joint the threads before deleting them.
The plot thickens. I haven't tried on Linux yet, but on Windows, I can
eliminate the thread lock with no error, but this doesn't work on OSX.
When I remove the lock from the code, it gets a EXC_BAD_ACCESS on the
shutdown_ flag itslef. Here is a little more information.
The library is setting connecting to streams of data and recording them
to a local file. There is one new thread created per stream and in that
thread a function is called that has an infinite loop in it:
while (true) {
// check for shutdown condition
{
boost::mutex::scoped_lock lock(phase_mut_);
if (shutdown_)
break;
}
// code to do the data grabbing and writing
}
So, when thedestructor is called, the first thing to do is to put a lock
on the shutdown_ flag and switch it to true.The destructor then goes
through all the spawned threads and joins them.
>> Thanks for taking a look at this. This is a terrible way to have to
>> look at code, so I really appreciate any time spent.
>>
> You are welcome.
>
> Hoping this helps. If not I will need more code. You could send me
> privately if you prefer.
The code is open source anyway, I don't mind sharing anything. Here is
the entire source code file in question on github:
Thanks again,
David
>
> Vicente
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/boost-users
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net