|
Boost : |
Subject: Re: [boost] [threads] API Design Question
From: Alexander Bernauer (alex_at_[hidden])
Date: 2009-02-06 05:34:36
On Thursday 05 February 2009 15:25:50 Phil Endecott wrote:
> if you notify with the lock held the
> waiting thread may be scheduled but it will immediately block trying to
> re-acquire the mutex, and the first thread will be scheduled again to
> release it.
I checked the posix documentation and indeed it is not guaranteed that
the above does not happen. I didn't expect that.
> I haven't measured the effect this though.
Maybe some implementations are smart enough to avoid this scenario. At
least I hope so.
> Can you give an example?
In my case, I have two event queues. One for immediate events and one
for delayed ones, i.e. something like
std::queue<Event*> imQ;
std::priority_queue<std::pair<system_time, Event*> > delQ;
Both queues are encapsulated by a "meta"-queue class providing
void push(Event*, time_duration delay=not_a_date_time) and
Event* pop()
Besides normal queue semantics the meta queue has the additional
constraint that a delayed event may not be returned by pop() before its
delivery time has been reached.
Without spurious wakeups, we would have
---8<---
void push(Event* event, time_duration delay=not_a_date_time)
{
lock l(mutex);
if (delay == not_a_date_time) {
imQ.push(event);
} else {
delQ.push(std::make_pair(get_system_time() + delay, event));
}
condition.notify();
}
--->8---
and
---8<---
Event* pop()
{
lock l(mutex);
while(1) {
if (not imQ.emtpy()) {
Event* event = imQ.top(); imQ.pop(); return event;
} else {
if (not delQ.empty()) {
const system_time now = get_system_time();
if (delQ.top().first < now) {
Event* event = delQ.top().second; delQ.pop(); return event;
} else {
condition.timed_wait(l, delQ.top().first); // (1)
}
} else {
condition.wait(l); // (2)
}
}
}
}
--->8---
While writing those lines I realized that the above code is correct even
if there are spurious wakeups. My point was that (1) becomes
---8<---
while (imQ.empty()
and get_system_time() < delQ.top().first
and condition.timed_wait(l, delQ.top().first));
--->8---
and (2) becomes
---8<---
while(imQ.empty() and delQ.empty()) { condition.wait(); }
--->8---
but this is not necessary.
Maybe the above is a general pattern to avoid complicated loop
conditions for spurious wakeups. If this is true, besides convenience, I
have no argument left for encapsulating spurious wakeups.
Thank you
regards
Alexander
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk