Does the following snippet show undefined behavior?

W

Wake up Brazil

I've been told that this code shows undefined behavior because of §3.6.3/4 in the C++11 Standard, but I don't understand this assertion.

#include <iostream>
#include <thread>

class A
{
public:
void operator()() const { std::cout << 'A' << '\n'; }
};

int main()
{
std::thread t(A{});
t.detach();
}

The problem here is that cout may be used in the thread t after the end of main().

My interpretation of §3.6.3/4 (applied to cout) is as follows: if there is a use of cout in a signal handler that does not happen before completion of destruction of objects with static storage duration ..., the program hasundefined behavior.

But the code above doesn't use cout in a signal handler. Thus, AFAIK this paragraph doesn't apply in this case.
 
W

Wake up Brazil

This paragraph says that only the same very limited subset of stuff can be used
in other threads after destruction of statics.

That's not what I understand reading §3.6.3/4. Can you explain what you said above?

§3.6.3/4:

"If there is a use of a standard library object or function not permitted within signal handlers (18.10) that does not happen before (1.10) completionof destruction of objects with static storage duration and execution of std::atexit registered functions (18.5), the program has undefined behavior."
 
W

Wake up Brazil

Your understanding is incorrect. Read §3.6.3/4 again and see my

separate response (which also gives you a solution if you happen to be

using a POSIX-like OS such as the BSDs, linux, Solaris, HPUX and so

forth: but note that with linux you need to be running a 2.6/3.* kernel

to get the behaviour you want).



Chris

That's clear already. See my prior post. Thanks.
 
W

Wake up Brazil

§27.4.1/2:

The objects are constructed and the associations are established at some time prior to or during the first time an object of class ios_base::Init is constructed, and in any case before the body of main begins execution. The objects are not destroyed during program execution. The results of including<iostream> in a translation unit shall be as if <iostream> defined an instance of ios_base::Init with static storage duration. Similarly, the entire program shall behave as if there were at least one instance of ios_base::Init with static storage duration.

From this, one concludes that std::cout is not destroyed during program execution. If that is the case, why does §3.6.3/4 mandate that a detached thread, using cout after completion of destruction of objects with static storage duration, shows undefined behavior? After all, cout will be available until the thread is finished.

See also this paragraph obtained from Nicolai Jesuttis' book:

http://books.google.com.br/books?id...=c++ when do detached threads finish?&f=false

"Because std::cin, std::cout and std::error and the other global stream objects according to the Standard "are not destroyed during program execution", access to these objects in detached threads should introduce no undefinedbehavior."
 
W

Wake up Brazil

It will not. The process will terminate when main() returns,

irrespective of the state of the detached thread. If you put a sleep in

your worker thread before it prints you will see that std::cout never

prints, as the program does not wait for the sleep to terminate before

exiting.



Having said that, I was unaware of $27.4.1/2, which is new in C++11.

What it seems to require, when read with footnote 295, is that

std::cout is the last static object to have its destructor called, and

that it must not be destroyed before all exit handlers have returned.

But that will not help you if you have a detached thread trying to

access it while it is undergoing destruction. The only way to deal

with this in POSIX-like OSs is to call pthread_exit() as I have said.

If you do that, you will see that the program will not terminated until

the worker thread has completed.



Chris

If the process terminates when main() returns, irrespective of the state ofthe detached thread, as you said, then what is the purpose of §3.6.3/4 as applied to cout in my example? In this scenario (the process terminating when main is finished), as the detached thread is part of the process, there will never be a cout being used in a detached thread after completion of destruction of objects with static storage duration!

Also, what do you say about Nicolai Jesuttis' comment on his book?
 
W

Wake up Brazil

Wake up Brazil writes:












The detached thread is racing with the thread that caused the process to exit,

which means the thread could access the object while it is being destructed.

I believe that another question begs to be answered, before we continue with the original discussion: in my example, is the process terminated when main() is finished, or when the detached thread is finished?
 
Ö

Öö Tiib

I believe that another question begs to be answered, before we continue with
the original discussion: in my example, is the process terminated when main()
is finished, or when the detached thread is finished?

Returning from main is like calling exit(), so objects with static
duration are destroyed and all threads (including the main thread) are
abruptly terminated (without calling thread exit handlers and so on).
Threads are *terminated* in that scenario not finished, only 'atexit'
is called.

So roughly put if you don't care when and how a thread ends then
you may detach it and if you do care then don't detach it but join it.
Since your thread uses static object ('std::cout') the behavior of your
program is undefined.
 
W

Wake up Brazil

Returning from main is like calling exit(), so objects with static

duration are destroyed and all threads (including the main thread) are

abruptly terminated (without calling thread exit handlers and so on).

Threads are *terminated* in that scenario not finished, only 'atexit'

is called.



So roughly put if you don't care when and how a thread ends then

you may detach it and if you do care then don't detach it but join it.

Since your thread uses static object ('std::cout') the behavior of your

program is undefined.

Ok, let's assume the process is terminated right after the end of main(), so that my worker thread may still execute std::cout << 'A' << '\n'; after the condition imposed by §3.6.3/4. According to this clause the code is UB.. My question is, given that §27.4.1/2 says that cout is not destroyed during program execution, why using cout in a detached thread like the one inthe example has to show undefined behavior?

For example, everybody knows that

int* p = new int;
delete p;
delete p;

has undefined behavior. The informal explanation is simply, you can't delete the same object twice. What I'm looking for is an informal explanation for the fact that my example is UB, given that paragraph §27.4.1/2 seems tocontradict this.

Then I showed a page from Nicolai Josuttis' book where he seems to have exactly the same concern as I do now. To finalize, I would say, that the last thing I would think about, is that this is boring.
 
Ö

Öö Tiib

Ok, let's assume the process is terminated right after the end
of main(), so that my worker thread may still execute
std::cout << 'A' << '\n'; after the condition imposed
by §3.6.3/4. According to this clause the code is UB.

My question is, given that §27.4.1/2 says that cout is not
destroyed during program execution, why using cout in a
detached thread like the one in the example has to show
undefined behavior?

Isn't it enough that you have UB by §3.6.3/4? Or are you
asking why the §3.6.3/4 classifies it as UB?
For example, everybody knows that

int* p = new int;
delete p;
delete p;

has undefined behavior. The informal explanation is simply,
you can't delete the same object twice. What I'm looking
for is an informal explanation for the fact that my example
is UB, given that paragraph §27.4.1/2 seems to contradict
this.

Informally your program is possibly terminated in
middle of output. It is undetermined if it outputs
anything and what it is. Hard to call it "defined"?
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top