[Boost-users] boost::mutex::scoped_lock crashes on OSX

142 views
Skip to first unread message

David Medine

unread,
Dec 15, 2015, 2:11:54 PM12/15/15
to boost...@lists.boost.org
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

It seems like this is becausem->_sig is now empty for some reason, but I
can not determine why (XCode's debugger won't let me 'watch' this
variable) but it should certainly be the case that it doesn't get
touched between the apparently successful constructor routines and now.

This all happens on OSX Yosemite. I am compiling my extension with
LLVM6.1 and I have gnu++0x as the C++ language dialect and libc++ as the
stdlib. I am linking statically to boost 1.57 which I built using this
command:

sudo ./b2 -a cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++"
toolset=clang link=static link=shared threading=multi install
--prefix=/opt/local --layout-tagged

THX!
-David

_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Vicente J. Botet Escriba

unread,
Dec 16, 2015, 12:41:49 PM12/16/15
to boost...@lists.boost.org
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

{
boost::mutex::scoped_lock lock(phase_mut_);
shutdown_ = true;
}

while on the destructor?

Vicente

David Medine

unread,
Dec 16, 2015, 1:35:10 PM12/16/15
to boost...@lists.boost.org
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.
}

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.

Vicente J. Botet Escriba

unread,
Dec 16, 2015, 4:58:35 PM12/16/15
to boost...@lists.boost.org
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.
> 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.

Vicente

David Medine

unread,
Dec 17, 2015, 5:14:29 PM12/17/15
to boost...@lists.boost.org
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:

https://github.com/sccn/labstreaminglayer/blob/master/Apps/LabRecorder/src/RecorderLib/RecorderLib/recording.h

Thanks again,
David
Reply all
Reply to author
Forward
0 new messages