boost::mutex - are lock attempts queued?

L

Lars Uffmann

I have 2 threads, master thread setting a keepalive flag, child thread
checking that flag:

master thread function to end child thread:

boost::mutex::scoped_lock lc (mutexAccessKeepalive, true);
if (keepAlive)
keepAlive = 0;
lc.unlock();


child thread main loop:

boost::mutex::scoped_lock lc (mutexAccessKeepalive, true);
while (keepAlive) {
lc.unlock();
// do some stuff
lc.lock();
}
lc.unlock();

In general, this works fine.
However, if the "// do some stuff" part (in this case listening for udp
traffic) gets cut short (failed to bind socket) and exits fast, my
master thread fails to acquire the lock on the mutex EVER. If I put a
"sleep (1);" there, it works fine again and the child thread ends as
intended.

I thought that attempts to lock an object were queued in boost, in the
order the request was made? What happens here seems to indicate that my
child thread is unlocking the mutex, and locks it again, before the main
thread has a chance to "snatch" the lock.

Does anyone have an explanation and a workaround? :)

Best Regards,

Lars
 
L

Lars Uffmann

okay, another time I misjudged the problem.

I have a race condition.
What's happening is that my child thread is accessing GUI resources. And
for that, it is trying to acquire a lock on those, which is not gonna
happen while my main thread is waiting for a lock on the data.

Have to chew on this a bit, but I guess I need to find a better solution :)

Best Regards,

Lars
 
L

Lionel B

I have 2 threads, master thread setting a keepalive flag, child thread
checking that flag:

master thread function to end child thread:

boost::mutex::scoped_lock lc (mutexAccessKeepalive, true); if
(keepAlive)
keepAlive = 0;
lc.unlock();
[...]

Please note that this newsgroup is for C++ *language* issues only. Try
asking in a forum where this is on-topic (one of the Boost forums, maybe?)
 
F

Fei Liu

Lars said:
I have 2 threads, master thread setting a keepalive flag, child thread
checking that flag:

lock attempts are never queued. lock is acquired when a lock is not
bound and a thread attempts to acquire it.

However, the operating system can employ priority based or round robin
scheduling to ensure each thread has priority based or equal opportunity
at acquiring a lock.

There is some kind of scheduling going on behind your back but it's
orthogonal to user scheduling of lock attempts.
 
L

Lars Uffmann

Lionel said:
Please note that this newsgroup is for C++ *language* issues only. Try
asking in a forum where this is on-topic (one of the Boost forums, maybe?)

Congratulations on using the first chance at trolling when I leave out
the disclaimer. boost is definitely on-topic here. Get used to it. Please.

...

Lars
 
L

Lars Uffmann

Fei said:
lock attempts are never queued. lock is acquired when a lock is not
bound and a thread attempts to acquire it.

Hmm... I'm not sure what the C++ standardization committee is about to
implement, but the "basis" for that implementation in boost seems to be
queueing lock attempts:

- thread a gets a lock on mutex m
- thread b attempts to acquire a lock on m, and locks
- thread a unlocks m
- thread b now gets the lock on m and proceeds

That's how it is behaving. Just for the record :)

Best Regards,

Lars
 
L

Lionel B

Congratulations on using the first chance at trolling when I leave out
the disclaimer. boost is definitely on-topic here.

http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.9

"Only post to comp.lang.c++ if your question is about the C++ language
itself. For example, C++ code design, syntax, style, rules, bugs, etc.
Ultimately this means your question must be answerable by looking into
the C++ language definition as determined by the ISO/ANSI C++ Standard
document, and *by planned extensions and adjustments*."

Hmph. Ok, some of Boost - even Boost.Thread - might fall under "planned
extensions and adjustments", but certainly not the whole of Boost.
 
J

Joe Greer

okay, another time I misjudged the problem.

I have a race condition.
What's happening is that my child thread is accessing GUI resources.
And for that, it is trying to acquire a lock on those, which is not
gonna happen while my main thread is waiting for a lock on the data.

Have to chew on this a bit, but I guess I need to find a better
solution :)

Best Regards,

Lars


You would probably get more expert help from comp.programming.threads, but
since threads are being added to the standard, I think that some discussion
here should be allowed.

One thing to keep in mind is that mutex' are not necessarily fair. That
is, if you release a mutex and immediately try to reacquire it, the system
may grant you that access because you are already set up to use it. It is
implementation defined as to what happens.

joe
 
L

Lars Uffmann

Joe said:
One thing to keep in mind is that mutex' are not necessarily fair. That
is, if you release a mutex and immediately try to reacquire it, the system
may grant you that access because you are already set up to use it. It is
implementation defined as to what happens.

Yikes!
I was afraid something like that might be the case...

Plus I now have to understand how wxWidgets treats its locks... :/

Thank you for the feedback!

Lars
 
P

Paavo Helde

Hmm... I'm not sure what the C++ standardization committee is about to
implement, but the "basis" for that implementation in boost seems to be
queueing lock attempts:

- thread a gets a lock on mutex m
- thread b attempts to acquire a lock on m, and locks
- thread a unlocks m

Typically, OS gives each thread a quantum of processor time to execute.
If thread a unlocks m in the middle of this quantum, OS may notice that
thread b is waiting on that mutex and wake up b immediately - or it might
not, allowing for thread a to use its time quantum fully. If during this
time thread a attempts to relock the mutex it will probably succeed and
thread b remains waiting.

Boost has not really a chance to affect this, thread scheduling is done
by OS. Boost could in principle build a serialized layer over the OS
primitives, but AFAIK it has not done this (because of no need, and
performance degradation).
- thread b now gets the lock on m and proceeds

That's how it is behaving. Just for the record :)

This is how the locking mechanism is expected to work in general.
However, there is no guarantee that exactly thread b will get the lock if
several threads are waiting on the mutex.

If the child thread is about to react to some external events like
termination request, it should wait on a boost::condition if it has
nothing else to do. If it is busy in a tight loop and wants to relock the
mutex all the time, it should use boost::thread::yield() to give other
threads a better chance to grab the mutex meanwhile.

Best regards
Paavo
 
S

Szabolcs Ferenczi

Does anyone have an explanation and a workaround? :)

My guess is that your worker thread just goes to the next `do some
stuff' since the flag is still on. Your master thread resets the flag
but your worker hangs somewhere in `do some stuff'.

The workaround is that you explain what you want to achieve and we can
help you coming up with a thread compliant design for your problem.

Best Regards,
Szabolcs
 
L

Lars Uffmann

Paavo said:
If the child thread is about to react to some external events like
termination request, it should wait on a boost::condition if it has
nothing else to do. If it is busy in a tight loop and wants to relock the
mutex all the time, it should use boost::thread::yield() to give other
threads a better chance to grab the mutex meanwhile.

Thank you for even more input, I will take this into consideration when
I continue on the project in two weeks.

Best Regards,

Lars
 
L

Lars Uffmann

Szabolcs said:
The workaround is that you explain what you want to achieve and we can
help you coming up with a thread compliant design for your problem.

I think Paavo came up with what I need to do.

I'm trying to access two different types of data with two different
threads: master thread = GUI (wxWidgets) event handlers, child thread =
continuous boost::thread network traffic handler.

The master thread shall be able to signal the child thread to terminate,
that makes up one of the data types I need to access there: a keepalive
flag for the thread (or boost::condition, in the future). The other type
of data is GUI controls, upon which wxWidgets holds a lock (of its own
type) while any event handler is running, and the child thread can only
access these for reading or writing when no GUI event handler is active.

So a possible timeline goes like (* = child thread running, x = event
handler):

x disable child thread status control on GUI
x change GUI status control to "stop child thread"
x start child thread (button event handler)
x* end event handler
* enable child thread status control on GUI
* handle network traffic until user clicks a button to end child thread
* ...
* (user presses button "end child thread")
x* disable child thread status control on GUI
x* change GUI status control to "start child thread"
x* signal child thread to exit
x* send a predefined packet to get child thread out of listening mode
x* end event handler
* end current network servicing loop
* enable child thread status control on GUI
* end child thread

All the time, the child thread will update status indicators on the GUI,
which can only be accessed while no event handler is running.

Best Regards,

Lars
 
G

Gerhard Fiedler

Hmm... I'm not sure what the C++ standardization committee is about to
implement, but the "basis" for that implementation in boost seems to be
queueing lock attempts:

- thread a gets a lock on mutex m
- thread b attempts to acquire a lock on m, and locks
- thread a unlocks m
- thread b now gets the lock on m and proceeds

That's how it is behaving. Just for the record :)

There is no "queue" here. Ok, there is a queue of 1 thread waiting -- but
with one member, there's no difference between a stack, a queue, a set, ...
:)

The thing is if several threads b1, b2, b3, ... are waiting on m (and have
attempted to acquire the lock in that order), there is nothing in the
language that guarantees that they will acquire the lock in that order. If
so, it would be a queue. It's not, so it isn't really a queue.

Gerhard
 
Y

Yannick Tremblay

http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.9

"Only post to comp.lang.c++ if your question is about the C++ language
itself. For example, C++ code design, syntax, style, rules, bugs, etc.
Ultimately this means your question must be answerable by looking into
the C++ language definition as determined by the ISO/ANSI C++ Standard
document, and *by planned extensions and adjustments*."

Hmph. Ok, some of Boost - even Boost.Thread - might fall under "planned
extensions and adjustments", but certainly not the whole of Boost.

Sorry but Boost is generally considered on topic here.

I think there's a difference between what Lars posted and the newbie
posting:
-------------------------------------
#include "proprietary_lib_header.h"
foo()
{
proprietary_object bar(some_unknown_datatype);
bar.someUnknownInterface();
}

It doesn't work!!!!! Please solve my problem for me.
 
Y

Yannick Tremblay

lock attempts are never queued. lock is acquired when a lock is not
bound and a thread attempts to acquire it.

However, the operating system can employ priority based or round robin
scheduling to ensure each thread has priority based or equal opportunity
at acquiring a lock.

There is some kind of scheduling going on behind your back but it's
orthogonal to user scheduling of lock attempts.

End it is probably better that way.

IMO, multithreaded programs should have each thread assume that it
works totally asynchronously from any other threads. Sure one can
wait on a condition if needed but apart from that, no order of
execution should be assumed.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,900
Latest member
Nell636132

Latest Threads

Top