Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Bog in condition_variable_any wait_for

70 views
Skip to first unread message

Fred.Zwarts

unread,
Jun 9, 2017, 5:15:43 AM6/9/17
to
I wanted to change a 10 years old program, which uses native
(windosw/pthreads) multi-threading code, to use instead the C++11 classes
for mutexes, conditions and threads, for better portability.

I now encounter a problem with the wait_for function of the
condition_variable_any class. I was able to reduce it to a small program,
see below.

The program sets up a duration of 10 seconds and then calls wait_for with
this duration. In a program without threads, the condition cannot be
signalled, so I expect that it would time out after 10 seconds.
The duration is using a resolution of clock ticks, because that was the unit
with which the original program worked.
This expected behavior is indeed what happens on my Raspberry Pi and
sometimes under Windows. However, sometimes under Windows 10 (VS 2015) and
always under Linux (SLES12, g++ 4.8.5) the wait_for returns with no_timeout
status, under Windows after 10 seconds, under SLES12 after a few clock
ticks.
I now concentrate on the SLES12 environment, where it is easier to
reproduce.
Even more strange (under SLES12) is that if I add code that uses the
pthread_create function, then the bug disappears, even if this code is not
used in the program. (Define the BUGOFF macro.) This smells like undefined
behavior, but I cannot find what is wrong in the code.

I wonder if this could also be a compiler bug, but apparently two very
different compilers are affected.

I would like your help. Can anybody spot the undefined behavior, or are
similar problems known in compilers? If it is a compiler problem, how do I
report it?

-------- Program source:

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <ratio>

using std::chrono::duration;

using std::condition_variable_any;
using std::cv_status;

using std::cout;
using std::endl;

using std::mutex;

using std::ratio;

// Define a duration type in units of clock ticks.

#include <time.h> // For CLK_TCK or CLOCKS_PER_SEC
#if !defined (CLK_TCK)
# if defined (CLOCKS_PER_SEC)
# define CLK_TCK CLOCKS_PER_SEC
# else
# error CLK_TCK not defined
# endif
#endif

const clock_t Tck1Sec (CLK_TCK);
typedef duration <clock_t, ratio <clock_t (1), Tck1Sec>> ClockDuration_t;

// If the following macro is defined under Linux then the bug disappears.

//#define BUGOFF

#ifdef BUGOFF
#include <pthread.h>
void Dummy () {
pthread_create (0, 0, 0, 0);
}
#endif

int main () {

// Define a duration of 10 seconds.

const ClockDuration_t WaitDuration (10 * Tck1Sec);

mutex TestMutex;
condition_variable_any TestCondition;

cout << "Let the condition time-out in 10 seconds." << endl;

TestMutex.lock ();
for (int Count = 0; Count < 10; ++Count) {

// Expected behavior is that in a program with only the main thread
// there is no thread to signal the condition, so the "wait_for"
// function should return after 10 seconds with the cv_status::timeout
// value. However, it returns with a value cv_status::no_timeout, both
// under Windows (sometimes) and Linux (SLES12) (always), under
// Windows after 10 seconds, under Linux after a few clock ticks.

if (TestCondition.wait_for (TestMutex, WaitDuration)
!= cv_status::no_timeout) {
cout << "Timeout: " << endl;
break;
}
cout << "No timeout: " << endl;
}

TestMutex.unlock ();
}

Melzzzzz

unread,
Jun 9, 2017, 5:22:55 AM6/9/17
to
On 2017-06-09, Fred.Zwarts <F.Zw...@KVI.nl> wrote:
>
> I would like your help. Can anybody spot the undefined behavior, or are
> similar problems known in compilers? If it is a compiler problem, how do I
> report it?

Condition variable suffers from spurious wakeups, so that it is never
enough just to wait on condition, rather to test some condition
accompanying it.

--
press any key to continue or any other to quit...

Fred.Zwarts

unread,
Jun 9, 2017, 5:52:45 AM6/9/17
to
"Melzzzzz" schreef in bericht news:ohdpd7$73c$3...@news.albasani.net...
>
>On 2017-06-09, Fred.Zwarts <F.Zw...@KVI.nl> wrote:
>>
>> I would like your help. Can anybody spot the undefined behavior, or are
>> similar problems known in compilers? If it is a compiler problem, how do
>> I
>> report it?
>
>Condition variable suffers from spurious wakeups, so that it is never
>enough just to wait on condition, rather to test some condition
>accompanying it.
>

Yes, I know, but in this case the wait_for becomes effectively a busy
CPU-bound loop. I don't think that spurious wakeups are an excuse to
transfor wait_for in a busy loop.
Please, understand that the demo program is only to demonstrate the bug, not
to do anything useful.

Melzzzzz

unread,
Jun 9, 2017, 5:55:10 AM6/9/17
to
It is not bug. Even sleep does not have to sleep, rather it can be
interrupted (EINTR).

Alain Ketterlin

unread,
Jun 9, 2017, 6:54:56 AM6/9/17
to
"Fred.Zwarts" <F.Zw...@KVI.nl> writes:

> "Melzzzzz" schreef in bericht news:ohdpd7$73c$3...@news.albasani.net...
>>
>>On 2017-06-09, Fred.Zwarts <F.Zw...@KVI.nl> wrote:
>>>
>>> I would like your help. Can anybody spot the undefined behavior, or are
>>> similar problems known in compilers? If it is a compiler problem,
>>> how do I
>>> report it?
>>
>>Condition variable suffers from spurious wakeups, so that it is never
>>enough just to wait on condition, rather to test some condition
>>accompanying it.
>>
>
> Yes, I know, but in this case the wait_for becomes effectively a busy
> CPU-bound loop. I don't think that spurious wakeups are an excuse to
> transfor wait_for in a busy loop.

No, wait_for will still quietly wait most of the time, but your program
_must_ be prepared for spurious wakeups. In your case the logic is:

1) lock the mutex
2) while (logical-condition-not-true and no-timeout-occurred)
...wait_for...
3) unlock mutex

As Melzzzzz explained, the logical condition is whatever you are waiting
for (typically, some shared variable test). You cannot just use the
condition-variable for signaling, because of spurious wakeups.

-- Alain.

Fred.Zwarts

unread,
Jun 9, 2017, 7:21:10 AM6/9/17
to
"Alain Ketterlin" schreef in bericht
news:8737b9m...@universite-de-strasbourg.fr.invalid...
I know, but you are missing the point.
A spurious wakeup every nanosecond is not reasonable.
The for loop is there only to limit the output. A while (true) loop would
output millions of lines a time-out simply never happens, because the
wait_for always returns immediately with a no_timeout status.
Do you really think that the following is a valid implementation of
wait_for?

cv_status wait_for (Lock& lck,
const chrono::duration<Rep,Period>& rel_time) {
return cv_status::no_timeout;
}

I don't call that a spurious wake up. But that is effectively what wait_for
is doing in my case.
It constantly returns immediately with a no_timeout status.
That is what I want to demonstrate in this program.
If I do what you say, then there would be a CPU-bound loop for 10 seconds
and the bug would go unnoticed.
(In fact, that was what happened in the original program.)

Please note, that this program is there to demonstrate a bug, not to explain
a good use of wait_for.

Can you explain why the mere presence of pthread_create changes the behavior
of wait_for so drasticly?

Melzzzzz

unread,
Jun 9, 2017, 8:17:04 AM6/9/17
to
On 2017-06-09, Fred.Zwarts <F.Zw...@KVI.nl> wrote:
>
> Can you explain why the mere presence of pthread_create changes the behavior
> of wait_for so drasticly?

Because condition is probably implemented in terms of pthreads, that is,
probably, if there is only one thread, implementation passes through
instead of deadlocking. On Haskell RT eg, system throws exception in
such cases.

Fred.Zwarts

unread,
Jun 9, 2017, 8:20:34 AM6/9/17
to
"Melzzzzz" schreef in bericht news:ohdr9k$73c$7...@news.albasani.net...
So, you think the following is a reasonable implementation of sleep:

int sleep (int) {
return EINTR;
}

Melzzzzz

unread,
Jun 9, 2017, 8:33:31 AM6/9/17
to
Why do you think so?

Fred.Zwarts

unread,
Jun 9, 2017, 8:46:24 AM6/9/17
to
"Melzzzzz" schreef in bericht news:ohe4ii$j47$2...@news.albasani.net...
Because I told you that my wait_for loop became effectively a busy loop and
then you continued to say that even sleep does not have to sleep.

Fred.Zwarts

unread,
Jun 9, 2017, 8:51:52 AM6/9/17
to
"Fred.Zwarts" schreef in bericht news:ohdovj$1b9g$1...@gioia.aioe.org...
OK, after further searching the Internet, I found that this is due to a very
obscure bug in g++ environment when the C++ multi-threading classes are
used.
One need to specify the linker options
--no-as-needed -lpthread
in programs where the C++ multi-threading classes are used, unexpected
behavior pops up.

Melzzzzz

unread,
Jun 9, 2017, 9:21:35 AM6/9/17
to
On 2017-06-09, Fred.Zwarts <F.Zw...@KVI.nl> wrote:
>
> OK, after further searching the Internet, I found that this is due to a very
> obscure bug in g++ environment when the C++ multi-threading classes are
> used.
> One need to specify the linker options
> --no-as-needed -lpthread
> in programs where the C++ multi-threading classes are used, unexpected
> behavior pops up.
>

Nowhere you mentioned g++... you need -pthread , yes. --no-as-needed for
other reasons, as I remember. That is corrected in later versions.

Fred.Zwarts

unread,
Jun 9, 2017, 9:57:37 AM6/9/17
to
In my original post I mentioned "Linux (SLES12, g++ 4.8.5)"
I understand that -lpthread is needed. (In fact I used it already.)
The need for --no-as-needed is a bug.

Apparently the support for the C++ multi-threading classes is not yet
mature.

Melzzzzz

unread,
Jun 9, 2017, 9:59:09 AM6/9/17
to
Try newer compiler.

Chris Ahlstrom

unread,
Jun 10, 2017, 12:48:03 PM6/10/17
to
Fred.Zwarts wrote this copyrighted missive and expects royalties:
Melzzz meant that in some cases it does not need to sleep.

--
Mind! I don't mean to say that I know, of my own knowledge, what there is
particularly dead about a door-nail. I might have been inclined, myself,
to regard a coffin-nail as the deadest piece of ironmongery in the trade.
But the wisdom of our ancestors is in the simile; and my unhallowed hands
shall not disturb it, or the Country's done for. You will therefore permit
me to repeat, emphatically, that Marley was as dead as a door-nail.
-- Charles Dickens, "A Christmas Carol"

Chris Ahlstrom

unread,
Jun 11, 2017, 9:51:44 AM6/11/17
to
Melzzzzz wrote this copyrighted missive and expects royalties:
gcc/g++ are up to version 6.3 (at least) now.

Maybe Fred doesn't want to pay the license fee to upgrade :-).

--
The lunatic, the lover, and the poet,
Are of imagination all compact...
-- Wm. Shakespeare, "A Midsummer Night's Dream"

Fred.Zwarts

unread,
Jun 12, 2017, 7:41:49 AM6/12/17
to
"Chris Ahlstrom" schreef in bericht news:ohjhmh$e7l$1...@dont-email.me...
>
>Melzzzzz wrote this copyrighted missive and expects royalties:
>
>> On 2017-06-09, Fred.Zwarts <F.Zw...@KVI.nl> wrote:
>>> On 2017-06-09, Fred.Zwarts <F.Zw...@KVI.nl> wrote:
>>>>>
>>>>> OK, after further searching the Internet, I found that this is due to
>>>>> a
>>>>> very
>>>>> obscure bug in g++ environment when the C++ multi-threading classes
>>>>> are
>>>>> used.
>>>>> One need to specify the linker options
>>>>> --no-as-needed -lpthread
>>>>> in programs where the C++ multi-threading classes are used, unexpected
>>>>> behavior pops up.
>>>>>
>>>>
>>>>Nowhere you mentioned g++... you need -pthread , yes. --no-as-needed for
>>>>other reasons, as I remember. That is corrected in later versions.
>>>
>>> In my original post I mentioned "Linux (SLES12, g++ 4.8.5)"
>>> I understand that -lpthread is needed. (In fact I used it already.)
>>> The need for --no-as-needed is a bug.
>>>
>>> Apparently the support for the C++ multi-threading classes is not yet
>>> mature.
>>>
>> Try newer compiler.
>
>gcc/g++ are up to version 6.3 (at least) now.
>
>Maybe Fred doesn't want to pay the license fee to upgrade :-).

I have no choice. It is not my system. I have to live with the compiler that
is installed on this system.

Jorgen Grahn

unread,
Jun 16, 2017, 1:35:24 AM6/16/17
to
On Fri, 2017-06-09, Fred.Zwarts wrote:
> "Fred.Zwarts" schreef in bericht news:ohdovj$1b9g$1...@gioia.aioe.org...
>>
>>I wanted to change a 10 years old program, which uses native
>>(windosw/pthreads) multi-threading code, to use instead the C++11 classes
>>for mutexes, conditions and threads, for better portability.
>>
>>I now encounter a problem with the wait_for function of the
>>condition_variable_any class. I was able to reduce it to a small program,
>>see below.
...
>
> OK, after further searching the Internet, I found that this is due to a very
> obscure bug in g++ environment when the C++ multi-threading classes are
> used.
> One need to specify the linker options
> --no-as-needed -lpthread
> in programs where the C++ multi-threading classes are used, unexpected
> behavior pops up.

Nice!

Could you please post an URL for the bug too, for the benefit of
others who encounter this problem?

(I'm not affected myself, but it's always good to "anchor" a
discussion like the one above in an official bug report.)

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Fred.Zwarts

unread,
Jun 26, 2017, 4:01:52 AM6/26/17
to
"Jorgen Grahn" schreef in bericht
news:slrnok6rgg.10...@frailea.sa.invalid...
I found it here:
"Jorgen Grahn" schreef in bericht
news:slrnok6rgg.10...@frailea.sa.invalid...
I found it here:
https://stackoverflow.com/questions/19463602/compiling-multithread-code-with-g


0 new messages