Bug 58929 - condition_variable does not wait without -pthread
Summary: condition_variable does not wait without -pthread
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.8.1
: P3 minor
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-10-30 20:10 UTC by Johan Lundberg
Modified: 2020-11-23 11:05 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Johan Lundberg 2013-10-30 20:10:26 UTC
A warning would have been helpful for this case of missed -pthread. 
Normally a runtime error is at least generated but the following C++11 code compiles fine with all warnings enabled, and also executes without run time errors, but does so incorrectly if -pthread is not given. (wait_for is then just skipped). 

cheers Johan.

#include <chrono>
#include <mutex>
#include <condition_variable>
void sleep10(){ // sleeps only of -pthread is used
  std::mutex m;
  std::condition_variable cv;
  std::unique_lock<std::mutex> lk(m);
  cv.wait_for(lk,std::chrono::seconds{10}); 
}
Comment 1 Jonathan Wakely 2013-10-31 11:29:45 UTC
I'm not really sure what we can do here. You need to use -pthread.
Comment 2 Jonathan Wakely 2013-10-31 11:31:20 UTC
I suppose we could turn all timed waiting functions into sleeps, and wait() into an infinite loop, when libpthread is not linked in, but I'd prefer not to add that complexity.
Comment 3 Johan Lundberg 2013-10-31 16:10:42 UTC
(In reply to Jonathan Wakely from comment #2)
> I suppose we could turn all timed waiting functions into sleeps, and wait()
> into an infinite loop, when libpthread is not linked in, but I'd prefer not
> to add that complexity.

I agree, that sounds too much.

The documentation of -pthread states that it sets flags for the preprocessor in addition to the linker and at least on my system, _REENTRANT is set by -pthreads. If that's a canonical way to detect threading support I suggest checking it in the headers that rely on threading:

#ifndef _REENTRANT
#error "No thread support enabled."
#endif

If there are reasons this is not a good idea so be it.
Comment 4 Jonathan Wakely 2013-10-31 16:18:45 UTC
I don't think -pthread sets _REENTRANT for all targets, although it might do for all those where we actually support std::condition_variable.
Comment 5 Jonathan Wakely 2013-10-31 16:20:28 UTC
Also, some people compile without -pthread then link with -lpthread manually. We could say that's technically unsupported, but currently it works.
Comment 6 Jakub Jelinek 2013-10-31 18:40:21 UTC
I'd say most people compile with -lpthread, I think glibc only keyes a single prototype on _REENTRANT (getlogin_r) and even that is also enabled by POSIX 1995
feature test macro too (which is on by default).
So, conditionalizing something on _REENTRANT sounds a wrong idea to me.
Comment 7 Jonathan Wakely 2014-09-19 11:04:28 UTC
related to PR 55394
Comment 8 Victor Mataré 2020-04-18 17:36:37 UTC
This has just caused me major headache because the behavior is completely unexpected. The root problem to me seems to be that pthread_cond_wait is defined not just in libphread, but also in libc:

# objdump -TC /lib/libc.so.6 | grep cond_wait
0014a570 g    DF .text  00000033 (GLIBC_2.0)  pthread_cond_wait
0007f5c0 g    DF .text  00000033  GLIBC_2.3.2 pthread_cond_wait

Why is that even in there? And if I apparently end up calling this implementation, why doesn't block the way it should?
Comment 9 Jonathan Wakely 2020-04-18 19:53:32 UTC
The GNU libc has no-op stubs for several pthread functions. I think that is done so that single threaded programs which don't actually need those functions can still link to libraries that have references to those functions.

They don't block because they're not for use in multithreaded programs. If you need the real versions you need to link to libpthread.
Comment 10 Victor Mataré 2020-04-19 00:10:39 UTC
(In reply to Jonathan Wakely from comment #9)
> The GNU libc has no-op stubs for several pthread functions. I think that is
> done so that single threaded programs which don't actually need those
> functions can still link to libraries that have references to those
> functions.
> 
> They don't block because they're not for use in multithreaded programs. If
> you need the real versions you need to link to libpthread.

OK, thanks for the clarification. But I feel I need to point out that that's just a huge WTF. How is a C++ dev supposed to know from the standard docs they work with all day that a condition_variable has any relation to libpthread? Least of all if you're used to getting linker errors if you're missing an implementation.

I've read up on it a little bit and I can understand the rationale for having no-op mutex-related stuff because that doesn't break behavior in single-threaded code. But wait conditions are supposed to (mostly) block, single-threaded or not. A no-op stub is a severe breach of protocol there because no one expects to get "spurious" wakeups at 100% CPU. Just think about something like this happening in a real-time system.

Maybe this should rather be a glibc bug. Any opinions on that?
Comment 11 Jonathan Wakely 2020-11-23 11:05:33 UTC
(In reply to Victor Mataré from comment #10)
> OK, thanks for the clarification. But I feel I need to point out that that's
> just a huge WTF. How is a C++ dev supposed to know from the standard docs
> they work with all day that a condition_variable has any relation to
> libpthread?

You're not compiling with the standard, you're using GCC. The requirement to use libpthread is documented by the implementation (although it could be easier to find):
https://gcc.gnu.org/onlinedocs/libstdc++/manual/using.html#manual.intro.using.flags