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

C++ condition variable confusion

184 views
Skip to first unread message

john...@nowhere.co.uk

unread,
Mar 14, 2019, 8:00:24 AM3/14/19
to
Hello all

I'm trying to understand the condition variables with 2011 threads but I'm
obviously missing something obvious. Can anyone see why the code below simply
hangs and the thread never leaves the wait() called? My understanding is that
wait() should exit immediately upon receiving a notification but this doesn't
happen.

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>

using namespace std;

mutex mt;
condition_variable cv;

void func()
{
unique_lock<mutex> ul(mt);
cout << "Thread waiting\n";
cv.wait(ul);
cout << "Thread done\n";
}


int main()
{
thread thr(func);
cout << "notifying\n";
cv.notify_one();
thr.join();
return 0;
}


What the (probably stupid) mistake I'm making?

Alf P. Steinbach

unread,
Mar 14, 2019, 8:22:50 AM3/14/19
to
On 14.03.2019 13:00, john...@nowhere.co.uk wrote:
> #include <iostream>
> #include <thread>
> #include <mutex>
> #include <condition_variable>
>
> using namespace std;
>
> mutex mt;
> condition_variable cv;
>
> void func()
> {
> unique_lock<mutex> ul(mt);
> cout << "Thread waiting\n";
> cv.wait(ul);
> cout << "Thread done\n";
> }
>
>
> int main()
> {
> thread thr(func);
> cout << "notifying\n";
> cv.notify_one();
> thr.join();
> return 0;
> }

The notification has to come after the thread has started waiting.


Cheers!,

- Alf

Paavo Helde

unread,
Mar 14, 2019, 8:44:41 AM3/14/19
to
Before notifying, you need to raise a flag under the mutex lock,
indicating that a notification is sent. This flag must be checked by the
other thread, again under the mutex lock, *before* waiting, typically in
a while loop to cope with spurious wakeups:

unique_lock<mutex> ul(mt);
while (!flag) {
cout << "Thread waiting\n";
cv.wait(ul);
}

Basically, whenever you see in your code cv.notify*() without some
variable change under a mutex lock, then it strongly smells for a data
race. Even if your data is atomic, you still need to lock the mutex for
synchronization.

Ditto for cv.wait() without a data variable check between the mutex lock
and wait. Another alternative is to use another wait() overload with a
proper predicate which performs this simple loop for you.

john...@nowhere.co.uk

unread,
Mar 14, 2019, 8:46:00 AM3/14/19
to
Ah, the notification isn't queued, I didn't know that. Is there a fullproof
way of the main thread waiting until sub threads are ready? Setting a flag
variable is subject to race conditions and so is calling sleep() unless you
set it to sleep for 10 seconds or something to be absolutely sure the thread
has reached wait()?

john...@nowhere.co.uk

unread,
Mar 14, 2019, 8:52:54 AM3/14/19
to
But its possible the main thread could set the flag and then call notify_one()
before this thread executes and then the notify will still be lost and this
thread will then still sit in wait() forever surely?



Paavo Helde

unread,
Mar 14, 2019, 9:06:36 AM3/14/19
to
That's why you check for the flag also *before* the waiting.


Scott Lurndal

unread,
Mar 14, 2019, 9:15:30 AM3/14/19
to
cond wait needs an associated predicate, e.g.:

/*
* Wait for the unit reference count to become one.
*/
inline void
c_file_card_unit::wait_for_delete(void)
{
pthread_mutex_lock(&cu_lock);
while (cu_refcount > 1) {
fprintf(stdout, "%4.4lu/%2.2lu Waiting for delete (refcnt=%lu)\n",
cu_channel, cu_unit, cu_refcount);
pthread_cond_wait(&cu_waiter, &cu_lock);
}
pthread_mutex_unlock(&cu_lock);
}

/*
* Decrement the unit reference count.
*/
inline ulong
c_file_card_unit::operator--(int)
{
ulong rval;

pthread_mutex_lock(&cu_lock);
rval = --cu_refcount;
if (rval == 0) {
pthread_cond_signal(&cu_waiter);
}
pthread_mutex_unlock(&cu_lock);

return rval;
}

john...@nowhere.co.uk

unread,
Mar 14, 2019, 12:24:14 PM3/14/19
to
On Thu, 14 Mar 2019 15:06:24 +0200
I don't think this will work. It still does not guarantee that the child
thread will arrive at wait() before the main thread has called notify_one().

Bonita Montero

unread,
Mar 14, 2019, 1:12:49 PM3/14/19
to
>> That's why you check for the flag also *before* the waiting.

> I don't think this will work. It still does not guarantee that the child
> thread will arrive at wait() before the main thread has called notify_one().

That's intended and this might result in a spurious wakeup of a thread.
I.e. the wakeup might be consumed by another thread. Because of that
the flag is checked in a loop to detect this kind of wakeups.

Paavo Helde

unread,
Mar 14, 2019, 2:48:48 PM3/14/19
to
On 14.03.2019 18:24, john...@nowhere.co.uk wrote:
>>>
>>>> unique_lock<mutex> ul(mt);
>>>> while (!flag) {
>>>> cout << "Thread waiting\n";
>>>> cv.wait(ul);
>>>> }
>>>
>>> But its possible the main thread could set the flag and then call
>> notify_one()
>>> before this thread executes and then the notify will still be lost and this
>>> thread will then still sit in wait() forever surely?
>>
>> That's why you check for the flag also *before* the waiting.
>
> I don't think this will work. It still does not guarantee that the child
> thread will arrive at wait() before the main thread has called notify_one().

That's true, but this guarantee is not needed for anything. If the flag
is already raised when the thread first comes around to lock the mutex,
then it will know it has been already notified, and will not call wait()
at all.

Maybe you are thinking that thread synchronizations can be done by
notify() and wait() only. Nope, for reliable synchronization you need
the share a data state and communicate the data state (a single bit flag
in this simple example). Mutexes, notifications and waits are just
helpers for making this data sharing fast and reliable.



john...@nowhere.co.uk

unread,
Mar 15, 2019, 5:58:51 AM3/15/19
to
Fair enough, but given that you can reliably synchronise seperate processes
using signals and/or IPC only it seems a pity the same can't be done with
threads just using system calls instead of having to rely on polling flags
too.

Sam

unread,
Mar 15, 2019, 7:09:16 AM3/15/19
to
john...@nowhere.co.uk writes:

> Fair enough, but given that you can reliably synchronise seperate processes
> using signals and/or IPC only it seems a pity the same can't be done with
> threads just using system calls instead of having to rely on polling flags
> too.

Signals are not thread safe. Apples and oranges. And you'll be surprised to
learn that IPC works in exactly the same way: use an internal shared state
variable, and the same mutexes and condition variables to coordinate the
activity between the threads.

If you really wish to call a single function to notify a thread, and another
function to wait for a notification, there is no law that says you can't.
Your first function simply has to a lock the mutex, increment a counter
variable, signal a condition variable, and return (and unlock the mutex).
Your second function has to lock the mutex, check if the shared counter is
0, and if so wait for the condition variable and go back to the previous
step; and when the shared counter is not 0, reset it back to 0 and return
the number of times it's been signaled (also after unlocking the mutex).

Abra-cadabra! Presenting: a single function for notifying a thread, and a
single function to reliably wait for the notification, if it hasn't been
already, and if the thread's already been notified, it returns the number of
times it's been notified. Now, you can feel free to pretend that's how
threads get notified in your entire application.


Öö Tiib

unread,
Mar 15, 2019, 8:44:14 AM3/15/19
to
What you mean by IPC? It usually means things like message queues, sockets
and/or pipes. These work great with threads as well.

Basically it is possible that such (thread safe) message queues (pipe can
be viewed as one to one message queue and socket as two pipes in
opposite directions) to be the only way to transfer data between threads.
No data has to be shared otherwise. It simplifies lot of things and we can
use condition variable for building such thread safe message queues but
it is not working like message queue on its own (like your OP code seemed
to expect).

Paavo Helde

unread,
Mar 15, 2019, 9:10:12 AM3/15/19
to
I'm not so familiar with signals, but isn't it so that in a
single-threaded app a typical (non-fatal) signal handler sets a *flag*
which is periodically *polled* by the main app?

Also, when starting up a new process, how do you know how long you have
to wait for it to set up the signal handlers, before you can send
signals to it? Seems a harder problem to me with processes than with
threads.

> it seems a pity the same can't be done with
> threads just using system calls instead of having to rely on polling flags
> too.

Wait+notify is usually not called polling; instead, it is a mechanism to
avoid polling. It's also important what it is not: it is not a mechanism
for encoding the program state, the program state is still best encoded
by data variables. So when one receives a notification one has to go and
study the program state to decide what to do next.

For example, you complained that std::condition_variable notifications
are not queued. Queuing a notification would not be so useful as there
may be several different notifications in general and one would not know
which notifications exactly are in the queue, not to speak about
spurious wake-ups which would look like ghost notifications.

Instead, in C++ you can easily build your own inter-thread queue,
holding custom notification aka event objects, potentially containing
tons of attached data. Such a queue can be built e.g. by using a
std::deque object, a mutex and a condition variable. The deque would
constitute the shared data state which I'm talking about all the time.

As usual, the C++ core language gives you the tools to build things, not
ready-made solutions. The notify mechanism is intentionally minimal
(notifications can be lost or appear from a thin air, no data attached
to the notifications, etc.) in order to not get in the way of
implementing solutions on top of it.


Öö Tiib

unread,
Mar 15, 2019, 9:34:40 AM3/15/19
to
From https://en.wikipedia.org/wiki/Signal_(IPC)
"When a signal is sent, the operating system interrupts the target process'
normal flow of execution to deliver the signal. Execution can be
interrupted during any non-atomic instruction. If the process has previously
registered a signal handler, that routine is executed. Otherwise, the
default signal handler is executed."

Bonita Montero

unread,
Mar 15, 2019, 9:36:02 AM3/15/19
to
> Fair enough, but given that you can reliably synchronise seperate processes
> using signals and/or IPC only it seems a pity the same can't be done with
> threads just using system calls instead of having to rely on polling flags
> too.

Thread-synchronization with condition-variables in the manner you've
been presented here is usually magnitudes more efficient than relying
only on kernel-facilities.
The downside of the usual condition-variables in this way is just
that there might be spurious or stolen wakeups; but this happens
not very often.

Scott Lurndal

unread,
Mar 15, 2019, 9:36:18 AM3/15/19
to
Perhaps you should instead investigate using sem_post(2)/sem_wait(2)?

Scott Lurndal

unread,
Mar 15, 2019, 10:32:14 AM3/15/19
to
And "deliver the signal" means run the registered (signal(2) or sigaction(2))
handler. Which often sets a flag that is polled by the app main loop.

john...@nowhere.co.uk

unread,
Mar 15, 2019, 12:17:24 PM3/15/19
to
They do, but using them means you get the extra complexity of their API
without the safety that seperate processes provide.

john...@nowhere.co.uk

unread,
Mar 15, 2019, 12:24:51 PM3/15/19
to
On Fri, 15 Mar 2019 07:09:03 -0400
Sam <s...@email-scan.com> wrote:
>This is a MIME GnuPG-signed message. If you see this text, it means that
>your E-mail or Usenet software does not support MIME signed messages.
>The Internet standard for MIME PGP messages, RFC 2015, was published in 1996.
>To open this message correctly you will need to install E-mail or Usenet
>software that supports modern Internet standards.
>
>--=_monster.email-scan.com-153254-1552648143-0001
>Content-Type: text/plain; format=flowed; delsp=yes; charset="UTF-8"
>Content-Disposition: inline
>Content-Transfer-Encoding: 7bit
>
>john...@nowhere.co.uk writes:
>
>> Fair enough, but given that you can reliably synchronise seperate processes
>> using signals and/or IPC only it seems a pity the same can't be done with
>> threads just using system calls instead of having to rely on polling flags
>> too.
>
>Signals are not thread safe. Apples and oranges. And you'll be surprised to
>learn that IPC works in exactly the same way: use an internal shared state
>variable, and the same mutexes and condition variables to coordinate the
>activity between the threads.

How a subsystem works internally is irrelevant , its what the application
programmer has to do that matters.

>If you really wish to call a single function to notify a thread, and another
>function to wait for a notification, there is no law that says you can't.

Sure, but should I have to? If I write data to a pipe or a message queue or a
socket it doesn't vanish into a black hole if the receiver doesn't immediately
read from it. It stays there until a read occurs so avoiding data loss and race
conditions. I don't see why the thread notify can't be the same.

>Abra-cadabra! Presenting: a single function for notifying a thread, and a
>single function to reliably wait for the notification, if it hasn't been
>already, and if the thread's already been notified, it returns the number of
>times it's been notified. Now, you can feel free to pretend that's how
>threads get notified in your entire application.

Meanwhile with socket & pipe based IPC I can just sit in a select(). No faffing
about with control variables and mutexes. When data arrives the function exits
whether that data was written before it was entered or after.

Chris Vine

unread,
Mar 15, 2019, 2:36:54 PM3/15/19
to
You have received a number of answers about how to correct your code
with a while loop and a flag. However, you might care to note that C++11
comes with a convenience overload for std::condition_variable::wait()
which takes a predicate and so avoids the need to code your own while
loop, namely:

void wait(std::unique_lock<std::mutex>& lock, Predicate pred);

This:

wait(lock, pred)

is equivalent to:

while (!pred()) {
wait(lock);
}

Condition variables are called "condition" variables for a reason,
which is that they require a predicate. Your code failed to provide one.

Chris M. Thomasson

unread,
Mar 15, 2019, 11:20:43 PM3/15/19
to
On 3/14/2019 10:12 AM, Bonita Montero wrote:
>>> That's why you check for the flag also *before* the waiting.
>
>> I don't think this will work. It still does not guarantee that the child
>> thread will arrive at wait() before the main thread has called
>> notify_one().
>
> That's intended and this might result in a spurious wakeup of a thread.

Indeed.

> I.e. the wakeup might be consumed by another thread. Because of that
> the flag is checked in a loop to detect this kind of wakeups.

Ditto.

Chris M. Thomasson

unread,
Mar 15, 2019, 11:23:11 PM3/15/19
to
On 3/14/2019 5:00 AM, john...@nowhere.co.uk wrote:
> Hello all
>
> I'm trying to understand the condition variables with 2011 threads but I'm
> obviously missing something obvious. Can anyone see why the code below simply
> hangs and the thread never leaves the wait() called? My understanding is that
> wait() should exit immediately upon receiving a notification but this doesn't
> happen.
[...]

A condition needs a predicate. Loop on it while waiting on the condvar.
Mutate the predicate under protection of the mutex, signal or broadcast
depending on what your state is designed to do.

Fwiw, there are some interesting places where one needs to use broadcast
instead of signal. A signal can go to any thread. A lot of people over
the years really do miss the predicate in the condvar wait. They seem to
mistakenly treat like some sort of event.

Imvvho, read the following book several times:

https://www.amazon.com/Programming-POSIX-Threads-David-Butenhof/dp/0201633922

Then, read it again... ;^)

Alf P. Steinbach

unread,
Mar 16, 2019, 8:17:58 AM3/16/19
to
I expressed the first program, on page 14 of the 1997 edition, in C++:


-----------------------------------------------------------------------------
// A C++ version of “alarm.c” on page 14 of “Programming with Posix
threads” 1997.

#include <cppx-core/_all_.hpp> //
https://github.com/alf-p-steinbach/cppx-core
$use_std( streambuf, cin, cout, cerr, endl, istream, string, getline, ws );
$use_namespace_names_in( std, chrono, this_thread );

void clear( istream& stream )
{
stream.clear();
stream.sync();
streambuf* p_buf = stream.rdbuf();
while( p_buf->in_avail() > 0 ) { p_buf->sbumpc(); }
}

auto main()
-> int
{
for( ;; )
{
cout << "Alarm> ";
int n_seconds;
string message;
const bool ok_input = (cin >> n_seconds >> ws and getline( cin,
message ));
if( not ok_input )
{
cerr << "Bad command" << endl;
clear( cin );
continue;
}
this_thread::sleep_for( chrono::seconds( n_seconds ) );
cout << "(" << n_seconds << ") " << message << endl;
}
}
-----------------------------------------------------------------------------


Not sure if I'm going on with the idea of expressing all those programs
in C++.

It may be very slow going.


Cheers!,

- Alf



john...@nowhere.co.uk

unread,
Mar 16, 2019, 8:46:36 AM3/16/19
to
On Fri, 15 Mar 2019 18:36:36 +0000
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
>On Thu, 14 Mar 2019 12:45:51 +0000 (UTC)
>john...@nowhere.co.uk wrote:
>> Ah, the notification isn't queued, I didn't know that. Is there a fullproof
>> way of the main thread waiting until sub threads are ready? Setting a flag
>> variable is subject to race conditions and so is calling sleep() unless you
>> set it to sleep for 10 seconds or something to be absolutely sure the thread
>> has reached wait()?
>
>You have received a number of answers about how to correct your code
>with a while loop and a flag. However, you might care to note that C++11
>comes with a convenience overload for std::condition_variable::wait()
>which takes a predicate and so avoids the need to code your own while
>loop, namely:
>
> void wait(std::unique_lock<std::mutex>& lock, Predicate pred);

I know.

>This:
>
> wait(lock, pred)
>
>is equivalent to:
>
> while (!pred()) {
> wait(lock);
> }

And that solves what? If its going to spin on a predicate you might just as
well write your own flag based spin loop and not bother with condition
variables in the first place.


Bo Persson

unread,
Mar 16, 2019, 9:08:51 AM3/16/19
to
It still waits on the lock, but rechecks the condition when it wakes up.


Bo Persson

Sam

unread,
Mar 16, 2019, 9:22:15 AM3/16/19
to
john...@nowhere.co.uk writes:

> On Fri, 15 Mar 2019 07:09:03 -0400
> >If you really wish to call a single function to notify a thread, and another
> >function to wait for a notification, there is no law that says you can't.
>
> Sure, but should I have to? If I write data to a pipe or a message queue or a
> socket it doesn't vanish into a black hole if the receiver doesn't
> immediately
> read from it. It stays there until a read occurs so avoiding data loss and
> race
> conditions. I don't see why the thread notify can't be the same.

Should you have to write a long and complicated C++ program to do a
particular task, correctly? Why can't you just #include some header file,
and have everything happen, by magic!

> >Abra-cadabra! Presenting: a single function for notifying a thread, and a
> >single function to reliably wait for the notification, if it hasn't been
> >already, and if the thread's already been notified, it returns the number of
> >times it's been notified. Now, you can feel free to pretend that's how
> >threads get notified in your entire application.
>
> Meanwhile with socket & pipe based IPC I can just sit in a select(). No

So, go ahead and do it. There is no law that says you can't create a pipe,
have one of your threads write to it, and the other one of your threads read
from it.

> faffing
> about with control variables and mutexes. When data arrives the function
> exits
> whether that data was written before it was entered or after.

This is how threads, mutexes, and condition variables work. You can either
use them correctly, or bitch about them on Usenet to anyone who cares. Your
choice. Sometimes life is not fair, and simple things become difficult, or
there are complications. Most people learn that by their late teens.

Most people also learn that if they find it difficult to turn a screw by
hand, they can go and get a tool called a "screwdriver". Similarly, there's
a shitload of C++ libraries out there that implement tools to wrap C++
thread primitives into higher-level constructs, that one can use directly.

C++ is not a kitchen sink programming language, full of magic buttons one
needs to only push, and have everything happen correctly. The C++ library
provides basic primitives, and one needs to learn how to use them correctly.
C++ never had a reputation for instant gratification, and is the most
complex general purpose programming language in use today.

Why there are even libraries out there that implement design patterns that
force you, by contract, to lock a mutex before being able to access a mutex-
protected object, and have the related condition variable notifiable only
when holding a lock on the mutex; and basically make it logically impossible
to use mutexes and condition variables incorrectly.

Isn't modern technology great?

Paavo Helde

unread,
Mar 16, 2019, 9:53:31 AM3/16/19
to
You could, but your program would consume 100% CPU with spinning, versus
0% with wait.

Why don't you try out different variants by yourself and see how they
behave? You are just banging your head against the wall now.

Scott Lurndal

unread,
Mar 16, 2019, 12:11:22 PM3/16/19
to
The difference, of course, is that 'wait' will cause the host operating system
schedulerr to schedule something else on that core/hardware thread (or put it
in a low-power state during the wait). A spin loop both prevents other processes
from getting CPU time as well as burns power.

Chris Vine

unread,
Mar 16, 2019, 4:38:25 PM3/16/19
to
You completely misunderstand this I am afraid.

First, you need to check when you begin the wait whether the condition
is already fulfilled, so you require as a minimum an if statement.
That was your original coding mistake. Secondly, in a perfect world,
having an if block would be enough, but it is specifically documented
by both POSIX and C++11 that a condition variable may spuriously wake
up for efficiency of implementation reasons. It happens very rarely,
but it can happen. So you use a while loop.

The while loop does not imply spinning as you seem to think.

Chris Vine

unread,
Mar 16, 2019, 4:50:39 PM3/16/19
to
On Sat, 16 Mar 2019 20:38:09 +0000
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
[snip]
> You completely misunderstand this I am afraid.
>
> First, you need to check when you begin the wait whether the condition
> is already fulfilled, so you require as a minimum an if statement.
> That was your original coding mistake. Secondly, in a perfect world,
> having an if block would be enough, but it is specifically documented
> by both POSIX and C++11 that a condition variable may spuriously wake
> up for efficiency of implementation reasons. It happens very rarely,
> but it can happen. So you use a while loop.

Add to this that it is also documented that signalling a condition
variable may wake up more than one thread - so you need a while loop
for that reason also if more than one thread may be waiting on the
variable. (And a broadcast is also obliged to wake up all threads
waiting on the condition variable, irrespective of whether the
condition is satisfied for all the waiting threads.)

Sam

unread,
Mar 17, 2019, 9:33:35 AM3/17/19
to
That brain surgeon does not understand how wait() works, and why it's needed?

I think we're looking at a future Microsoft Windows developer, here.


Alf P. Steinbach

unread,
Mar 17, 2019, 9:53:22 AM3/17/19
to
On 16.03.2019 04:23, Chris M. Thomasson wrote:
I coded up in C++ the second program from the book, page 15 in the 1997
edition, but it was apparently not possible to express it portably.

I found that I could express it so that it works in Windows in Unix, by
adding system-specific includes.

Apparently `waitpid` behaves differently in Windows WSL than in the Unix
the author used, or do I understand it incorrectly?


-------------------------------------------------------------------------
// A C++ version of “alarm_fork.c” on page 15 of “Programming with Posix
threads” 1997.

#ifdef _WIN32
# define IS_WINDOWS 1
# define IS_UNIX 0
#elif defined( __unix__ ) or (defined( __APPLE__ ) and defined( __MACH__ ))
# define IS_WINDOWS 0
# define IS_UNIX 1
#else
# error "Unsupported operating system."
#endif

#if IS_WINDOWS
# include <process.h> // execl
#elif IS_UNIX
# include <unistd.h> // execl, fork
# include <wait.h> // waitpid, should it better be
"<sys/wait.h>"?
#endif

#include <cppx-core/_all_.hpp> //
https://github.com/alf-p-steinbach/cppx-core
$use_cppx(
max_
);
$use_std(
streambuf, streamsize, cin, cout, cerr, endl, istream, getline,
ostringstream, ws,
string, quoted, stoi
);
$use_namespace_names_in( std, chrono, this_thread );
using namespace std::literals;

void clear( istream& stream )
{
if( stream.fail() )
{
stream.clear();
cin.ignore( max_<streamsize>, '\n' );
}
}

#if IS_WINDOWS
auto forked_or_is_windows() -> bool { return true; }
void delete_terminated_child_processes() {}
#elif IS_UNIX
auto forked_or_is_windows() -> bool { return fork() == 0; }
void delete_terminated_child_processes()
{
pid_t pid;
do
{
pid = waitpid( pid_t( -1 ), nullptr, WNOHANG );
if( pid == pid_t( -1 ) )
{
// This happens always in Windows' WSL environment, so
don't...
// $fail( "Wait for child" );
return;
}
} while( pid != 0 );
}
#endif

auto main( int n_args, char* args[] )
-> int
{
if( n_args == 3 )
{
if( *args[1] != '!' )
{
// We're in an ordinary program invocation with args; delegate.
if( forked_or_is_windows() )
{
string arg1 = "!"s + args[1];
return execl( args[0], args[0], arg1.c_str(), args[2],
nullptr );
}
return EXIT_SUCCESS;
}

const int n_seconds = stoi( args[1] + 1 );
const auto& message = args[2];
this_thread::sleep_for( chrono::seconds( n_seconds ) );
cout << "(" << n_seconds << ") " << message << endl;
}
else if( n_args == 1 )
{
for( ;; )
{
cout << "Alarm> ";
int n_seconds;
string message;
const bool ok_input = (cin >> n_seconds >> ws and getline(
cin, message ));
if( not ok_input )
{
cerr << "Bad command" << endl;
clear( cin );
continue;
}
ostringstream command_line;
command_line << args[0] << " " << n_seconds << " " <<
quoted( message );
system( command_line.str().c_str() );
delete_terminated_child_processes();
}
}
else
{
return EXIT_FAILURE;
}
}
-------------------------------------------------------------------------


Cheers!,

- Alf

john...@nowhere.co.uk

unread,
Mar 17, 2019, 12:41:44 PM3/17/19
to
On Sat, 16 Mar 2019 09:22:00 -0400
Sam <s...@email-scan.com> wrote:
>This is a MIME GnuPG-signed message. If you see this text, it means that
>your E-mail or Usenet software does not support MIME signed messages.

Perhaps don't use MIME in usenet.

>john...@nowhere.co.uk writes:
>
>> On Fri, 15 Mar 2019 07:09:03 -0400
>> >If you really wish to call a single function to notify a thread, and another
>
>> >function to wait for a notification, there is no law that says you can't.
>>
>> Sure, but should I have to? If I write data to a pipe or a message queue or a
>
>> socket it doesn't vanish into a black hole if the receiver doesn't
>> immediately
>> read from it. It stays there until a read occurs so avoiding data loss and
>> race
>> conditions. I don't see why the thread notify can't be the same.
>
>Should you have to write a long and complicated C++ program to do a
>particular task, correctly? Why can't you just #include some header file,
>and have everything happen, by magic!

Don't give up your day job, you won't make it as a comedian.


john...@nowhere.co.uk

unread,
Mar 17, 2019, 12:50:15 PM3/17/19
to
I still don't see the point of the above loop.

child thread:
while(!pred()) wait(lock);

- If predicate is set to false then go into the wait(). Thats fine, but then
the signalling thread calls notify but is then suspended, wait exits but
the flag has yet to be set to true for the above loop to exit and so the
receiving thread is now back in wait() again and now there is no notify for
it to see.

- If predicate is set to true then don't wait, carry on and ... do what?
If there are multiple threads they can't all do their own thing instead of
waiting and the above means that the signalling thread only has to set the
flag to true to make the receiving thread continue and doesn't even need to
bother with a notify().



john...@nowhere.co.uk

unread,
Mar 17, 2019, 12:51:43 PM3/17/19
to
On Sun, 17 Mar 2019 09:33:24 -0400
Sam <s...@email-scan.com> wrote:
>This is a MIME GnuPG-signed message. If you see this text, it means that
>your E-mail or Usenet software does not support MIME signed messages.
>The Internet standard for MIME PGP messages, RFC 2015, was published in 1996.
>To open this message correctly you will need to install E-mail or Usenet
>software that supports modern Internet standards.
>
>--=_monster.email-scan.com-26140-1552829604-0001
>Content-Type: text/plain; format=flowed; delsp=yes; charset="UTF-8"
>Content-Disposition: inline
>Content-Transfer-Encoding: 7bit
>
>Paavo Helde writes:
>
>> On 16.03.2019 14:46, john...@nowhere.co.uk wrote:
>>> And that solves what? If its going to spin on a predicate you might just as
>>> well write your own flag based spin loop and not bother with condition
>>> variables in the first place.
>>
>> You could, but your program would consume 100% CPU with spinning, versus 0%
>
>> with wait.
>
>That brain surgeon does not understand how wait() works, and why it's needed?

If I didn't understand why its needed sammy my little friend, I wouldn't be
trying to use it.

>I think we're looking at a future Microsoft Windows developer, here.

Huh huh huh, he's so funny Beavis, huh huh huh.

Ben Bacarisse

unread,
Mar 17, 2019, 1:56:52 PM3/17/19
to
john...@nowhere.co.uk writes:
<cut>
> I still don't see the point of the above loop.
>
> child thread:
> while(!pred()) wait(lock);

You may have got confused because of the term "condition variable".
It's a terrible name and has confused almost every student who comes
across them. There is no condition involved in the CV itself but they
are almost always used to wait for some condition being true. The CV
itself only holds a collection of blocked threads (usually in a queue)
one or more of which gets removed from the collection and run when the
CV is "notified".

It is very tempting, due to the name, to think of signalling as a way
indicate that some condition is now "true" -- a thread blocks on a
condition call "data_available" and the provider of that data signals
"data_available" through the CV. DO NOT THINK OF THEM THIS WAY. A CV
is too weak a mechanism for this. There must always be some external
data that indicates if the condition being waited on is, in fact, true.

This is why wait is associated with a mutex. The condition to be tested
and changed will usually require exclusive access to some data (if only
a flag) so wait unlocks the mutex and locks it again before returning.

Because a thread can be spuriously awakened, or maybe many threads are
all deliberately awakened, a thread must check to see that the data
setting it has been waiting for really are there -- that the flag is set
or the buffer has data in it, or whatever.

In general, while still holding the lock, an awakened thread should
reset the condition -- maybe it sets the flag to false or take data from
the buffer and sets the pointer to show that this is not more data.

It does not /have/ to do this. For example, a thread may take only some
of the data leaving more available. If it does so, the /awakened/ thread
should signal the CV to give some other thread a chance to take it.

> - If predicate is set to false then go into the wait(). Thats fine, but then
> the signalling thread calls notify but is then suspended, wait exits but
> the flag has yet to be set to true for the above loop to exit and so the
> receiving thread is now back in wait() again and now there is no notify for
> it to see.

That's a programming error. No thread should call notify unless it has
set up the shared data so as to make the waited on condition true. The
pattern is always: (a) set up the desired data structure (even if this
only flag = true), (b) call CV.notify.

> - If predicate is set to true then don't wait, carry on and ... do
> what?

That depends on what the purpose of the synchronisation was, but is
should probably set the flag back to false (or otherwise manipulate the
data to make the predicate false). If it does not, you most likely have
another programming error.

> If there are multiple threads they can't all do their own thing instead of
> waiting and the above means that the signalling thread only has to set the
> flag to true to make the receiving thread continue and doesn't even need to
> bother with a notify().

That's a busy loop and is not usually desirable.

--
Ben.

Chris M. Thomasson

unread,
Mar 17, 2019, 4:56:50 PM3/17/19
to
Iirc, there is an errata on some of the code. It has been a while since
I read it. However, the book will definitely teach somebody how to use a
condition variable. alarm_fork.c should be:

https://github.com/snikulov/prog_posix_threads/blob/master/alarm_fork.c

Chris Vine

unread,
Mar 17, 2019, 6:01:02 PM3/17/19
to
On Sun, 17 Mar 2019 17:56:40 +0000
Ben Bacarisse <ben.u...@bsb.me.uk> wrote:
> john...@nowhere.co.uk writes:
> > - If predicate is set to false then go into the wait(). Thats fine, but then
> > the signalling thread calls notify but is then suspended, wait exits but
> > the flag has yet to be set to true for the above loop to exit and so the
> > receiving thread is now back in wait() again and now there is no notify for
> > it to see.
>
> That's a programming error. No thread should call notify unless it has
> set up the shared data so as to make the waited on condition true. The
> pattern is always: (a) set up the desired data structure (even if this
> only flag = true), (b) call CV.notify.

To expand on this for the benefit of the original poster so he can
fully understand how condition variables work (I know you know all
this), as you mention the canonical way of using a flag with a
condition variable is as follows (this implies that there are 3 items
of shared data here, a boolean flag, a mutex and a condition variable):

Signalling thread, when it is ready to let the waiting thread proceed:

1. Locks the mutex.
2. Sets the flag to true.
3. Notifies on the condition variable.
4. Releases the mutex.

Often stage 4 is put before stage 3, as this is sometimes more
efficient and almost always as safe as releasing the mutex after the
notification. The OP will come across either approach.

Waiting thread:

1. Locks the mutex.
2. Tests the flag.
3a. If the flag is false, waits on the condition variable. On being
awoken later, go back to 2 again (that is, re-enter the while loop
and test the flag again).
3b. If the flag is true, sets the flag to false, releases the mutex
and does whatever else the thread is supposed to do on the
condition being satisfied.

One other point that may not be immediately apparent to the OP, but
which it is necessary for him to understand, is that when the waiting
thread starts waiting on the condition variable at stage 3a, the mutex
is automatically atomically unlocked by the system, which is what lets
the signalling thread have subsequent access to the flag. When the
waiting thread is awoken, the mutex is automatically atomically locked
again by the system, so the waiting thread then re-acquires sole access
to the flag.

One other thing for the OP to ponder is a case where there are multiple
threads involved. If all threads are notified (there is a
"broadcast"), every waiting thread will be awoken in turn and acquire
the mutex again, one at a time, in an order determined by the operating
system. So when the first thread to be released by the operating
system unlocks the mutex after resetting the flag, the next thread in
line will be released and acquire the mutex. Thus, every thread which
has been awoken will be able to determine whether the condition is
satisfied for it, or whether it should re-loop.

Sam

unread,
Mar 17, 2019, 9:04:53 PM3/17/19
to
john...@nowhere.co.uk writes:

> On Sat, 16 Mar 2019 09:22:00 -0400
> Sam <s...@email-scan.com> wrote:
> >This is a MIME GnuPG-signed message. If you see this text, it means that
> >your E-mail or Usenet software does not support MIME signed messages.
>
> Perhaps don't use MIME in usenet.

We use MIME in the 21st century.


Sam

unread,
Mar 17, 2019, 9:07:10 PM3/17/19
to
Just a few minutes ago you wrote:

"I still don't see the point of the above loop."

So you still don't understand it, apparently.

That's ok, someday you will.

It took me only a few minutes to figure it out, the first time I encountered
this topic, a long long time ago, in a galaxy far, far away.

But not everyone is as smart as me.

Sam

unread,
Mar 17, 2019, 9:12:51 PM3/17/19
to
Ben Bacarisse writes:

> john...@nowhere.co.uk writes:
> <cut>
> > I still don't see the point of the above loop.
> >
> > child thread:
> > while(!pred()) wait(lock);
>
> You may have got confused because of the term "condition variable".

Nah. He's not confused.

He's just butthurt because C++ is hard to learn, and hard to use correctly;
and he wishes it that C++ was much easier, and much simpler.

He was under the impression that one can slap together random pieces of C++
in random order, and as long as it compiles correctly it will work exactly
as intended, bug-free. But it's not exactly turning out according to plan,
and the dream of becoming an elite C++ uberhacker overnight is proving to be
quite elusive; hence the butthurt.


Ben Bacarisse

unread,
Mar 17, 2019, 9:35:57 PM3/17/19
to
Sam <s...@email-scan.com> writes:

> Ben Bacarisse writes:
>
>> john...@nowhere.co.uk writes:
>> <cut>
>> > I still don't see the point of the above loop.
>> >
>> > child thread:
>> > while(!pred()) wait(lock);
>>
>> You may have got confused because of the term "condition variable".
>
> Nah. He's not confused.
>
> He's just butthurt because C++ is hard to learn, and hard to use
> correctly; and he wishes it that C++ was much easier, and much
> simpler.

I disagree, but that's not really important because Usenet works best
when replies might be useful to more people than the one person the
reply appears to be to.

--
Ben.

Öö Tiib

unread,
Mar 18, 2019, 6:01:15 AM3/18/19
to
What you mean by complexity? Message queue is most conceivable
for human brain way to communicate between active threads.
It is general case: potentially lot of messages, from potentially
several threads, losslessly to one thread. Every other synchronization
element can be viewed as special (constrained or relaxed) case of it or
as component for building such. Separate processes just make it harder
to violate that logic. The "safety" when we use multiprocessing instead
of multithreading is against ourselves and unfortunately there are no
silver bullets against ourselves.

Chris Vine

unread,
Mar 18, 2019, 7:54:29 AM3/18/19
to
I think this elitist meme is misplaced. Bear in mind that there are
some language communities which consider that those who program in C++
are neanderthals because of the language's verbosity, weak type system
and/or difficulty in expressing some abstractions succinctly. C++ as a
programming language is considerably less popular than it once was,
probably in part because of these things (the prevalence of garbage
collection these days has probably also played a part).

The problem with learning to use condition variables (and for that
matter, windows event objects) correctly is that writing any
multi-threaded application with shared mutable state is difficult, and
more so when using primitives like condition variables and mutexes (and
even more so when using atomics).

rust seems to be the latest attempt to improve the concurrency
experience for shared state, with its linear/affine type system. Go's
built-in message passing and coroutines (goroutines) are also
interesting. and Erlang has had message passing as a core language
concept from the outset.

Sam

unread,
Mar 18, 2019, 9:24:43 PM3/18/19
to
Chris Vine writes:

> On Sun, 17 Mar 2019 21:12:42 -0400
> Sam <s...@email-scan.com> wrote:
>
> > He was under the impression that one can slap together random pieces of
> > C++ in random order, and as long as it compiles correctly it will work
> > exactly as intended, bug-free. But it's not exactly turning out
> > according to plan, and the dream of becoming an elite C++ uberhacker
> > overnight is proving to be quite elusive; hence the butthurt.
>
> I think this elitist meme is misplaced.

I wasn't claiming that C++ is some kind of an elite language. That's not
what I wrote. I was addressing someone's obvious posturing as some kind of a
C++ uberhacker and being full of amazing insights into how C++ should be
designed, and the disappointment at the lack of accolades, and agreement
with such greatness.

But, as long as this topic is on the table:

> Bear in mind that there are
> some language communities which consider that those who program in C++
> are neanderthals because of the language's verbosity, weak type system

You mean "strong type system". Unless black is suddenly white, it's hard to
find another general purpose language whose typing is stronger than C++. If
you filter all the noise, all the pleasedomyhomeworkforme.com,
pleasewritemycodeforme.com, and pleasegivemeananswertosomedumbquiz.com-type
posts on Stackoverflow, a good chunk of what's left are questions about some
typing-related compilation error.

As compared to declaring "var foo", say in Javascript, and throwing any kitchen
sink into it. Now that's what I call a weak type system.

And as far as verbosity goes, a lot of that is addressed by "auto", range
iterations, and similar recent features.

But, in any case, what other communities think, or don't think, of C++ did not
factor in my response.

> and/or difficulty in expressing some abstractions succinctly. C++ as a
> programming language is considerably less popular than it once was,
> probably in part because of these things (the prevalence of garbage
> collection these days has probably also played a part).

Of course. A long time ago you had no choice: you had to know your shit, in
order to write code that worked correctly, that didn't randomly crash, and
that didn't eat all the RAM you had. There were no other options. Either you
did C++ and got it right, or you changed careers.

Now, if you can't hack it, you can't wrap your brain around it, you can
always have the Java VM babysit everything for you, and change your diapers.
Forget about thinking with your brain. Create objects whenever you feel like
it, and the VM will take care of garbage-collecting everything to you. Just
make sure you have enough RAM. It's so much easier that way.

Before, if you didn't actually understand how things work, you were out. So,
naturally, C++ ruled the roost. There were no other options, hence, by
default, C++ had most of the mindshare.

But now, instead of leaving the field and go and do something else, the ones
who couldn't hack it, they were now able to write spaghetti code in Java. Or
Python. Or Perl. Or Javascript. So, of course C++'s market share is diluted.
There are so many options now, for those who can't hack C++, that didn't
exist before.

> The problem with learning to use condition variables (and for that
> matter, windows event objects) correctly is that writing any
> multi-threaded application with shared mutable state is difficult, and
> more so when using primitives like condition variables and mutexes (and
> even more so when using atomics).

That's exactly what I wrote. I am not disagreeing. C++ is hard. You have to
do things the right way. What I was commenting about is the whining about
C++ being hard, or supposedly not making the sense. That whining,
simultaneously with delusions of "why do have to things X way in C++ when
doing it Y way is either" self-grandeur. Why do you have to check the
protected state, before waiting on the condition variable? Why can't one
thread just push a magic button, and signal the other thread, now or later?

Well, because C++ does not work this way. C++ will always be hard. It's not
going to change. It's now about 5-7 times harder and bigger now, than
<C++11. It will never be easy. Wait until concepts land. That's going to be
one hell of a party.

James Kuyper

unread,
Mar 18, 2019, 10:44:32 PM3/18/19
to
On 3/18/19 21:24, Sam wrote:
> Chris Vine writes:
...
>> Bear in mind that there are
>> some language communities which consider that those who program in C++
>> are neanderthals because of the language's verbosity, weak type system
>
> You mean "strong type system". Unless black is suddenly white, it's hard to
> find another general purpose language whose typing is stronger than C++. If

See
<https://en.wikipedia.org/wiki/Comparison_of_programming_languages_by_type_system>
which lists C++ as weakly typed, and lists 70 other languages as
strongly typed. I don't claim Wikipedia is absolutely authoritative -
but if you think it's incorrect, please feel free to correct it.
The key thing that makes C++ more weakly typed than those other
languages is the large number of implicit conversions it supports.

Jorgen Grahn

unread,
Mar 19, 2019, 6:12:08 AM3/19/19
to
On Tue, 2019-03-19, James Kuyper wrote:
> On 3/18/19 21:24, Sam wrote:
>> Chris Vine writes:
> ...
>>> Bear in mind that there are
>>> some language communities which consider that those who program in C++
>>> are neanderthals because of the language's verbosity, weak type system
>>
>> You mean "strong type system". Unless black is suddenly white, it's hard to
>> find another general purpose language whose typing is stronger than C++. If
>
> See
> <https://en.wikipedia.org/wiki/Comparison_of_programming_languages_by_type_system>
> which lists C++ as weakly typed, and lists 70 other languages as
> strongly typed. I don't claim Wikipedia is absolutely authoritative -
> but if you think it's incorrect, please feel free to correct it.

A "this page lacks needed references" would be a good start.

> The key thing that makes C++ more weakly typed than those other
> languages is the large number of implicit conversions it supports.

A binary strong/weak separation isn't very useful (and it doesn't help
that "weak" sounds like a bad thing). C++ (and C) lets you mix char
and unsigned long, but not struct Foo and struct Bar (unless you add
conversion paths on purpose).

/Jorgen

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

Sam

unread,
Mar 19, 2019, 6:38:21 AM3/19/19
to
James Kuyper writes:

> On 3/18/19 21:24, Sam wrote:
> > Chris Vine writes:
> ...
> >> Bear in mind that there are
> >> some language communities which consider that those who program in C++
> >> are neanderthals because of the language's verbosity, weak type system
> >
> > You mean "strong type system". Unless black is suddenly white, it's hard to
> > find another general purpose language whose typing is stronger than C++. If
>
> See
> <https://en.wikipedia.org/wiki/Comparison_of_programming_languages_by_type_system>
> which lists C++ as weakly typed, and lists 70 other languages as
> strongly typed. I don't claim Wikipedia is absolutely authoritative -
> but if you think it's incorrect, please feel free to correct it.

I've read enough articles on Wikipedia itself, to know better than waste my
time like that.

> The key thing that makes C++ more weakly typed than those other
> languages is the large number of implicit conversions it supports.

Let's see, implicit conversions between numeric types, acquiring const-ness,
and implicit conversion of pointers/references to pointers/references to
base classes.

First of all, how many of those 70 other languages have char, short, int,
long, long long, the unsigned varieties, float and double? That's 12 numeric
types.

If you consider all of these as just one numeric type, like what I suspect
what happens in most of those 70 other languages, which probably have only
one, maybe two, numeric types, that's not a lot of implicit conversions.


James Kuyper

unread,
Mar 19, 2019, 8:08:10 AM3/19/19
to
On 3/19/19 06:11, Jorgen Grahn wrote:
> On Tue, 2019-03-19, James Kuyper wrote:
>> On 3/18/19 21:24, Sam wrote:
>>> Chris Vine writes:
>> ...
>>>> Bear in mind that there are
>>>> some language communities which consider that those who program in C++
>>>> are neanderthals because of the language's verbosity, weak type system
>>>
>>> You mean "strong type system". Unless black is suddenly white, it's hard to
>>> find another general purpose language whose typing is stronger than C++. If
>>
>> See
>> <https://en.wikipedia.org/wiki/Comparison_of_programming_languages_by_type_system>
>> which lists C++ as weakly typed, and lists 70 other languages as
>> strongly typed. I don't claim Wikipedia is absolutely authoritative -
>> but if you think it's incorrect, please feel free to correct it.
>
> A "this page lacks needed references" would be a good start.

Agreed. My original plan was to say "..., but you can follow up on the
references." - but there don't seem to be any that cover how the
languages are classified.

>> The key thing that makes C++ more weakly typed than those other
>> languages is the large number of implicit conversions it supports.
>
> A binary strong/weak separation isn't very useful (and it doesn't help
> that "weak" sounds like a bad thing).

Agreed. I was only addressing the question of whether C qualifies as a
strongly-typed langauge, not the desirability of doing so.

> ... C++ (and C) lets you mix char
> and unsigned long, but not struct Foo and struct Bar (unless you add
> conversion paths on purpose).

See section 4, "Standard Conversions" for the full list of conversions
that can occur implicitly - it's several pages long. In particular, see
paragraph 7. For standard types, you can, among other things, convert
long double to char, or a pointer to a struct to bool.

James Kuyper

unread,
Mar 19, 2019, 8:11:25 AM3/19/19
to
On 3/19/19 06:38, Sam wrote:
> James Kuyper writes:
...
>> See
>> <https://en.wikipedia.org/wiki/Comparison_of_programming_languages_by_type_system>
>> which lists C++ as weakly typed, and lists 70 other languages as
>> strongly typed. I don't claim Wikipedia is absolutely authoritative -
>> but if you think it's incorrect, please feel free to correct it.
>
> I've read enough articles on Wikipedia itself, to know better than waste my
> time like that.
>
>> The key thing that makes C++ more weakly typed than those other
>> languages is the large number of implicit conversions it supports.

I should also mention that C++ allows explicit conversions of types that
many strongly typed languages don't allow at all, particularly pointer
conversions.

> Let's see, implicit conversions between numeric types, acquiring const-ness,
> and implicit conversion of pointers/references to pointers/references to
> base classes.>
> First of all, how many of those 70 other languages have char, short, int,
> long, long long, the unsigned varieties, float and double? That's 12 numeric
> types.

Many of them have multiple arithmetic types, but don't have implicit
conversions between them.

Chris Vine

unread,
Mar 19, 2019, 8:19:32 AM3/19/19
to
On Mon, 18 Mar 2019 21:24:33 -0400
Sam <s...@email-scan.com> wrote:
> Chris Vine writes:
> > On Sun, 17 Mar 2019 21:12:42 -0400
> > Sam <s...@email-scan.com> wrote:
> > > He was under the impression that one can slap together random pieces of
> > > C++ in random order, and as long as it compiles correctly it will work
> > > exactly as intended, bug-free. But it's not exactly turning out
> > > according to plan, and the dream of becoming an elite C++ uberhacker
> > > overnight is proving to be quite elusive; hence the butthurt.
> >
> > I think this elitist meme is misplaced.
>
> I wasn't claiming that C++ is some kind of an elite language. That's not
> what I wrote. I was addressing someone's obvious posturing as some kind of a
> C++ uberhacker and being full of amazing insights into how C++ should be
> designed, and the disappointment at the lack of accolades, and agreement
> with such greatness.

It was you who was setting yourself up as a "C++ uberhacker", with your
"It took me only a few minutes to figure it out, the first time I
encountered this topic, a long long time ago, in a galaxy far, far
away. But not everyone is as smart as me." and "I think we're looking
at a future Microsoft Windows developer, here" and similar nonsense
intended to belittle someone else. (I fail to understand quite how you
managed to bring Windows developers into it; many of them are very
good.)

He was basically confused about what condition variables were and how
they were used, as beginners often are. His questions were reasonable
ones for a beginner; the most you could say is that he was somewhat
slow on the uptake, and may have argued the point more than you would
have liked, but people go at their own pace.

> But, as long as this topic is on the table:
>
> > Bear in mind that there are
> > some language communities which consider that those who program in C++
> > are neanderthals because of the language's verbosity, weak type system
>
> You mean "strong type system". Unless black is suddenly white, it's hard to
> find another general purpose language whose typing is stronger than C++.

You are wrong. This was one of the (in my view worthwhile) trade-offs
made when C++ was first designed in order to maintain compatibility
with C. C's built-in types have many implicit conversions available to
them, and what is more C has an undescriminated void* type. C++'s
class system is well typed, but every class at the end of the day is
formed from its built-in components.

[snip]
> As compared to declaring "var foo", say in Javascript, and throwing any kitchen
> sink into it. Now that's what I call a weak type system.

Javascript is relatively weakly typed - it does allow some coersions -
but the main distinguishing feature of "var foo" in Javascript compared
with "auto foo" in C++ is that Javascript has dynamic (latent) typing.
It is the object bound to 'foo' which is typed rather than the variable
name 'foo'. It is perfectly possible to have a language which is
strongly and dynamically typed, requiring some of the type checking to
be carried out at run time.
More of the same attitude. (By the way, you said above that you
"[weren't] claiming that C++ is some kind of an elite language".)

In any event, Python, Perl and Javascript are fishing in a different
pond from C++ and irrelevant to this - I don't think they have any
significant effect on C++ usage. My view is that C++ is a good
language for a number of the things that they don't do.

john...@nowhere.co.uk

unread,
Mar 19, 2019, 9:30:28 AM3/19/19
to
On Mon, 18 Mar 2019 21:24:33 -0400
Sam <s...@email-scan.com> wrote:
>This is a MIME GnuPG-signed message. If you see this text, it means that
>your E-mail or Usenet software does not support MIME signed messages.
>The Internet standard for MIME PGP messages, RFC 2015, was published in 1996.
>To open this message correctly you will need to install E-mail or Usenet
>software that supports modern Internet standards.
>
>--=_monster.email-scan.com-63302-1552958673-0001
>Content-Type: text/plain; format=flowed; delsp=yes; charset="UTF-8"
>Content-Disposition: inline
>Content-Transfer-Encoding: 7bit
>
>Chris Vine writes:
>
>> On Sun, 17 Mar 2019 21:12:42 -0400
>> Sam <s...@email-scan.com> wrote:
>>
>> > He was under the impression that one can slap together random pieces of
>> > C++ in random order, and as long as it compiles correctly it will work
>> > exactly as intended, bug-free. But it's not exactly turning out
>> > according to plan, and the dream of becoming an elite C++ uberhacker
>> > overnight is proving to be quite elusive; hence the butthurt.
>>
>> I think this elitist meme is misplaced.
>
>I wasn't claiming that C++ is some kind of an elite language. That's not
>what I wrote. I was addressing someone's obvious posturing as some kind of a
>C++ uberhacker and being full of amazing insights into how C++ should be
>designed, and the disappointment at the lack of accolades, and agreement
>with such greatness.

I would suggest that , in this order, you should:

A) Improve your English comprehension
B) Grow up.


Chris Vine

unread,
Mar 19, 2019, 9:57:15 AM3/19/19
to
On 19 Mar 2019 10:11:57 GMT
One problem with the yes/no approach is that most of the languages
marked as strongly typed have a FFI for C, for reasons of practicality.
This means that if the type system of your language does not allow you
to do some low level hack, you can do it in C and provide some
appropriate language-endorsed glue over it. However the code in that
case is still only as safe as the C code you have in fact written.

One thing you can say is that in such a case the area of weak typing is
confined to its own module. When you write an entire program in C it is
ubiquitous.

Sam

unread,
Mar 19, 2019, 6:00:23 PM3/19/19
to
You have my earnest assurances that your suggestions will receive the full
weight, and considerations, that they so richly deserve.

Sam

unread,
Mar 19, 2019, 6:02:45 PM3/19/19
to
Chris Vine writes:

> It was you who was setting yourself up as a "C++ uberhacker", with your
> "It took me only a few minutes to figure it out, the first time I
> encountered this topic, a long long time ago, in a galaxy far, far
> away. But not everyone is as smart as me."

It looks like a crucial fact was inadvertently omitted from this thoughtful
analysis. Specifically, the actual post that specific response was written
in reply to. Even more specific: the post in question was a 100% content-
free "you all suck" message; and my reply was pretty much in the same vein.
Perhaps I should've disclosed my policy that requires my response to be made
in the language the individual that I'm responding to is capable of
understanding. I just don't see the point of investing the time and effort
in assesmbling and putting together something that the intended recipient is
incapable of understanding.

But, obviously, that, in itself, was also too complicated for some to
understand.

> and "I think we're looking
> at a future Microsoft Windows developer, here" and similar nonsense
> intended to belittle someone else.

And that remark was responding to the proposal to replace wait() with a busy-
loop. The proposee, apparently, was either unable to understand the
difference, or was unaware how wait() works, in terms of CPU usage. Hence
the proper response.

But this was also too complicated for some to understand, from the looks of
it.

> (I fail to understand quite how you
> managed to bring Windows developers into it; many of them are very
> good.)

s/many/some/, and I might agree. But I'll have to disagree, as long as
things remain at such a generic level.

> He was basically confused about what condition variables were and how
> they were used, as beginners often are. His questions were reasonable
> ones for a beginner;

You left out trailing "… who belives that he's an expert and a know it all".

> the most you could say is that he was somewhat
> slow on the uptake,

That's a very modest understatement.

> > You mean "strong type system". Unless black is suddenly white, it's hard to
> > find another general purpose language whose typing is stronger than C++.
>
> You are wrong. This was one of the (in my view worthwhile) trade-offs
> made when C++ was first designed in order to maintain compatibility
> with C. C's built-in types have many implicit conversions available to
> them, and what is more C has an undescriminated void* type. C++'s
> class system is well typed, but every class at the end of the day is
> formed from its built-in components.

Oh, I wasn't aware that you could assign a std::variant to a double, or
push_back an instance of MyClass into a std::vector<int>, just like that. I
guess I was wrong, and C++ is a weakly-typed language.

James Kuyper

unread,
Mar 19, 2019, 8:43:03 PM3/19/19
to
On 3/17/19 12:51, john...@nowhere.co.uk wrote:
> On Sun, 17 Mar 2019 09:33:24 -0400
> Sam <s...@email-scan.com> wrote:
...
>> That brain surgeon does not understand how wait() works, and why it's needed?
>
> If I didn't understand why its needed sammy my little friend, I wouldn't be
> trying to use it.

I'm no expert on multi-threaded code, so I'll abstain from expressing
any judgments on whether or not your understanding of wait() is correct.
Also, I don't endorse Sam's insulting approach to this discussion.

However, I don't see how you can justify that argument. If you
misunderstood how wait() works, and misunderstood why it's needed, it
seems entirely reasonable to me that you would use wait() in any context
where your misunderstanding made using it seem, incorrectly, to be a
reasonable thing to do.

James Kuyper

unread,
Mar 19, 2019, 8:49:54 PM3/19/19
to
On 3/19/19 18:02, Sam wrote:
> Chris Vine writes:
...
>> You are wrong. This was one of the (in my view worthwhile) trade-offs
>> made when C++ was first designed in order to maintain compatibility
>> with C. C's built-in types have many implicit conversions available to
>> them, and what is more C has an undescriminated void* type. C++'s
>> class system is well typed, but every class at the end of the day is
>> formed from its built-in components.
>
> Oh, I wasn't aware that you could assign a std::variant to a double, or

Did anyone claim that you could? You can, however, assign a char to a
double, and vice versa.

> push_back an instance of MyClass into a std::vector<int>, just like that.

You can if MyClass has implicit conversion into any standard type that
can be implicitly converted to int.

> I
> guess I was wrong, and C++ is a weakly-typed language.

Compared to languages where the equivalent of

char c = 1.0;

is illegal, and must be re-written as the equivalent of

char c = char(1.0);

C++ is weakly typed.

Jorgen Grahn

unread,
Mar 20, 2019, 3:12:44 AM3/20/19
to
On Tue, 2019-03-19, James Kuyper wrote:
> On 3/19/19 06:11, Jorgen Grahn wrote:
>> On Tue, 2019-03-19, James Kuyper wrote:
...
>>> The key thing that makes C++ more weakly typed than those other
>>> languages is the large number of implicit conversions it supports.
>>
>> A binary strong/weak separation isn't very useful (and it doesn't help
>> that "weak" sounds like a bad thing).
>
> Agreed. I was only addressing the question of whether C qualifies as a
> strongly-typed langauge, not the desirability of doing so.

Yes. I noticed that, but it was a problem with the upthread postings.
The alternative term "loosely typed" would have been less controversial.

David Brown

unread,
Mar 20, 2019, 6:18:47 AM3/20/19
to
Note, however, that C++ /allows/ strong typing. It's base types are
fairly weak, just like C where they originated. But you can easily make
yourself types Char and Double that have very similar properties and
uses as char and double - but which are strongly typed and cannot be
implicitly converted.

So while there is no doubt that C++ is weakly typed at its lowest level,
it has support for strong typing. (It is a language that has support
for a good deal of paradigms and strategies in programming, without
insisting on their use.)

Alf P. Steinbach

unread,
Mar 20, 2019, 7:50:41 AM3/20/19
to
Well, imagine a city where there are traffic lights, but its up to the
car drivers whether to activate them and, when activated, obey them.

That is, the city /supports/ clean safe traffic, it provides the
necessary machinery, but it's all optional. The drivers can do that as
an agreed on convention. If they wish, and manage to agree.

That's safe, yes?


Cheers!,

- Alf

David Brown

unread,
Mar 20, 2019, 9:44:35 AM3/20/19
to
Fortunately, C++ is only ever programmed by people who understand what
they are doing, and program safely. And they never drunk-program.

:-)


Juha Nieminen

unread,
Mar 20, 2019, 10:47:32 AM3/20/19
to
James Kuyper <james...@alumni.caltech.edu> wrote:
> Compared to languages where the equivalent of
>
> char c = 1.0;
>
> is illegal, and must be re-written as the equivalent of
>
> char c = char(1.0);
>
> C++ is weakly typed.

I'm not sure what your definition of "weakly typed" is, but I have always
understood it as variables not having any particular type, and being able
to hold values of any type (without losing any info about that value).
So in a typical weakly typed language you don't specify the type of the
variable, and instead use a syntax that's typically like

var x = 5; // x holds an integer
var y = "hello"; // y holds a string
x = y; // ok, now x holds a string as well

What you are talking about is implicit conversions, which I'm not sure
are classically considered as related to weak/strong typing.

But even if we were talking about implicit conversions as "weak typing",
then C/C++ is only weakly typed among compatible types, so it's a very
limited form of "weakly typed".

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

james...@alumni.caltech.edu

unread,
Mar 20, 2019, 11:38:22 AM3/20/19
to
On Wednesday, March 20, 2019 at 10:47:32 AM UTC-4, Juha Nieminen wrote:
> James Kuyper <james...@alumni.caltech.edu> wrote:
> > Compared to languages where the equivalent of
> >
> > char c = 1.0;
> >
> > is illegal, and must be re-written as the equivalent of
> >
> > char c = char(1.0);
> >
> > C++ is weakly typed.
>
> I'm not sure what your definition of "weakly typed" is, but I have always

There are many possible definitions:
<https://en.wikipedia.org/wiki/Strong_and_weak_typing#Definitions_of_%22strong%22_or_%22weak%22>

> understood it as variables not having any particular type, and being able
> to hold values of any type (without losing any info about that value).
> So in a typical weakly typed language you don't specify the type of the
> variable, and instead use a syntax that's typically like
>
> var x = 5; // x holds an integer
> var y = "hello"; // y holds a string
> x = y; // ok, now x holds a string as well

What you're talking about is called "latent typing". There's a link to
the wikipedia page for "latent typing" on the wikipedia page about
"strong and weak typing", but there's no other indication of a link
between those two concepts.

> What you are talking about is implicit conversions, which I'm not sure
> are classically considered as related to weak/strong typing.

"implicit conversions" is the first of four items listed under the
section I gave a link to.

I want to emphasize that I'm not claiming Wikipedia is absolutely
authoritative. I just don't know of any other source that's any more
authoritative than Wikipedia. In my experience, Wikipedia is fairly
reliable when it comes to concepts related to computer science - more
so, in fact, than traditional encyclopedias. And if you find an error in
it, you're free to correct it (subject to review), which is an
improvement over traditional encyclopedias.

Chris Vine

unread,
Mar 20, 2019, 1:59:24 PM3/20/19
to
On Wed, 20 Mar 2019 14:47:20 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> James Kuyper <james...@alumni.caltech.edu> wrote:
> > Compared to languages where the equivalent of
> >
> > char c = 1.0;
> >
> > is illegal, and must be re-written as the equivalent of
> >
> > char c = char(1.0);
> >
> > C++ is weakly typed.
>
> I'm not sure what your definition of "weakly typed" is, but I have always
> understood it as variables not having any particular type, and being able
> to hold values of any type (without losing any info about that value).
> So in a typical weakly typed language you don't specify the type of the
> variable, and instead use a syntax that's typically like
>
> var x = 5; // x holds an integer
> var y = "hello"; // y holds a string
> x = y; // ok, now x holds a string as well

That is called dynamic or latent typing, which can be strong or weak.
The lisps and python are generally regarded as strongly and dynamically
typed. Javascript is weak-ish (all these things are on a continuum) and
dynamically typed. A strongly and dynamically typed language carries
out much of its type checking at run time. That obviously affects when
and how your type errors will propagate. The advantage of static
typing is that type errors are detected at compile time.

> What you are talking about is implicit conversions, which I'm not sure
> are classically considered as related to weak/strong typing.
>
> But even if we were talking about implicit conversions as "weak typing",
> then C/C++ is only weakly typed among compatible types, so it's a very
> limited form of "weakly typed".

I surprised there is any controversy about this. Languages which
give programmers leave to subvert the type system, and in particular
which provide implicit conversions and allow pointer conversions, are
generally referred to as weakly typed. C goes further and has a void*
type.

That is one of the reasons why C and C++ are suitable for low-level
systems programming and things which require maximum efficiency. But
you can call it whatever you like. "Not strongly typed" would be
fine. "Statically typed with loopholes" would also do. For C++ you
could say "statically and dynamically typed with loopholes", because
C++ has RTTI.

Chris M. Thomasson

unread,
Mar 20, 2019, 4:57:36 PM3/20/19
to
Well, some people think that the following is necessary to protect
people from themselves; cork on the fork, Steve Martin:

https://youtu.be/SKDX-qJaJ08

C and C++ allows one to pop the proverbial cork?

Jorgen Grahn

unread,
Mar 20, 2019, 6:17:43 PM3/20/19
to
On Tue, 2019-03-19, Sam wrote:

> Chris Vine writes:
>
>> It was you who was setting yourself up as a "C++ uberhacker", with your
>> "It took me only a few minutes to figure it out, the first time I
>> encountered this topic, a long long time ago, in a galaxy far, far
>> away. But not everyone is as smart as me."

> It looks like a crucial fact was inadvertently omitted from this
> thoughtful analysis. Specifically, the actual post that specific
> response was written in reply to. Even more specific: the post in
> question was a 100% content-free "you all suck" message; and my
> reply was pretty much in the same vein.

You were responding to a post from Ben, which was in response to the
OP's <q6ltrr$tsn$1...@gioia.aioe.org>. There's no "you all suck" theme
in that one AFAICT; it's a perfectly reasonable on-topic posting.

The OP /did/ whine a lot in other postings, but even those didn't
deserve your reaction upthread.

Jorgen Grahn

unread,
Mar 20, 2019, 6:39:09 PM3/20/19
to
On Wed, 2019-03-20, Chris Vine wrote:
> On Wed, 20 Mar 2019 14:47:20 +0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
...
>> But even if we were talking about implicit conversions as "weak typing",
>> then C/C++ is only weakly typed among compatible types, so it's a very
>> limited form of "weakly typed".
>
> I surprised there is any controversy about this. Languages which
> give programmers leave to subvert the type system, and in particular
> which provide implicit conversions and allow pointer conversions, are
> generally referred to as weakly typed. C goes further and has a void*
> type.

For me at least, I think the problem is I last encountered strong/weak
typing during my CS education[0] a long time ago.

Then at work I never touched a strongly typed language: no Ada or
Haskell, etc. Just languages with more or less loose type systems,
with different tradeoffs.

If you're comparing the languages you know and use, and find the C++
type system the most helpful of them, it's hard to swallow that it's
classified as "weak". Even though I'm sure it /is/ according to the
definition.

> That is one of the reasons why C and C++ are suitable for low-level
> systems programming and things which require maximum efficiency. But
> you can call it whatever you like. "Not strongly typed" would be
> fine. "Statically typed with loopholes" would also do. For C++ you
> could say "statically and dynamically typed with loopholes", because
> C++ has RTTI.

/Jorgen

[0] gu.se; they were heavily into type system research at the time, in
the various functional languages which became Haskell.

Chris Vine

unread,
Mar 20, 2019, 7:46:25 PM3/20/19
to
On 20 Mar 2019 22:38:57 GMT
Jorgen Grahn <grahn...@snipabacken.se> wrote:
> On Wed, 2019-03-20, Chris Vine wrote:
> > On Wed, 20 Mar 2019 14:47:20 +0000 (UTC)
> > Juha Nieminen <nos...@thanks.invalid> wrote:
> ...
> >> But even if we were talking about implicit conversions as "weak typing",
> >> then C/C++ is only weakly typed among compatible types, so it's a very
> >> limited form of "weakly typed".
> >
> > I surprised there is any controversy about this. Languages which
> > give programmers leave to subvert the type system, and in particular
> > which provide implicit conversions and allow pointer conversions, are
> > generally referred to as weakly typed. C goes further and has a void*
> > type.
>
> For me at least, I think the problem is I last encountered strong/weak
> typing during my CS education[0] a long time ago.
>
> Then at work I never touched a strongly typed language: no Ada or
> Haskell, etc. Just languages with more or less loose type systems,
> with different tradeoffs.
>
> If you're comparing the languages you know and use, and find the C++
> type system the most helpful of them, it's hard to swallow that it's
> classified as "weak". Even though I'm sure it /is/ according to the
> definition.

As I think you hint at, there seems to me to be a continuum and a trade
off. The guarantee of a strong statically typed language is that any
object passed to a function or other program interface which purports
to have (or must be inferred to have) a given type either (a) is of
that type, or (b) the program will fail to compile.

C and C++ do not, and in my view should not, offer that guarantee.
void* surpresses all static type information that the compiler
possesses, and sometimes you want that. More often, you want to be
able to cast to char* or unsigned char* to get at bytes and take the hit
of losing static type information, which in many usages doesn't matter.

On the other hand C++ does offer reasonable type guarantees if you
avoid casts. Using brace initialization also prevents implicit
narrowing conversions: 'int i{1.0}' won't compile. And as I have
mentioned elsewhere, the C++ class system itself is well typed.

If I were inventing a new language I would probably argue that unsafe
operations should be allowed for efficiency's sake, but that it should
only be possible to do them knowingly rather than accidentally, by
being explicitly elected for at the call site. I think that is what
rust does (but I do not have a firm handle on rust so I may be wrong
about that). For C++, compatibility with C is I think more important.

Öö Tiib

unread,
Mar 21, 2019, 8:40:10 AM3/21/19
to
On Wednesday, 20 March 2019 19:59:24 UTC+2, Chris Vine wrote:
>
> I surprised there is any controversy about this. Languages which
> give programmers leave to subvert the type system, and in particular
> which provide implicit conversions and allow pointer conversions, are
> generally referred to as weakly typed. C goes further and has a void*
> type.
>
> That is one of the reasons why C and C++ are suitable for low-level
> systems programming and things which require maximum efficiency. But
> you can call it whatever you like. "Not strongly typed" would be
> fine. "Statically typed with loopholes" would also do. For C++ you
> could say "statically and dynamically typed with loopholes", because
> C++ has RTTI.

Large part of C++ specification of most features of C++ is
explicitly telling us what all is undefined about that feature. So it is
only partially in control about most things (including type system).
That encourages us to set the rules of how strong, weak, dynamic
or static, safe or unsafe everything in it is ... ourselves.

0 new messages