Could you explain the point of difference between variable initialization sequence if a program starts and does not start a thread?
sec. 3.6.2/3 N3797 c++14 working draft:
If a program starts a thread (30.3), the subsequent initialization of
a variable is unsequenced with respect to the initialization of a
variable defined in a different translation unit. Otherwise, the
initialization of a variable is indeterminately sequenced with respect
to the initialization of a variable defined in a different translation
unit.
Please, give an example, explaining that rule, if it possible.
Unsequenced means there is no sequence - the variables could be initialised concurrently, on different threads.
Indeterminately sequenced means that one is sequenced before the other - the variables are initialised sequentially, on the same thread - but it's not specified which is initialised first.
Related
So I understand that re-usage of a variable that has been post incremented is undefined behavior in a function call. My understanding is this is not a problem in constructors. My question is about tie which is oddly halfway between each.
Given: pair<int, int> func() can I do:
tie(*it++, *it) = func();
Or is that undefined behavior?
Since C++17, this code has unspecified behavior. There are two possible outcomes:
the first argument is the result of dereferencing the original iterator, the second argument is the result of dereferencing the incremented iterator; or
the first argument and the second argument are both the result of dereferencing the original iterator.
Per [expr.call]/8:
[...] The initialization of a parameter, including every associated
value computation and side effect, is indeterminately sequenced with
respect to that of any other parameter. [...]
So the second argument to tie may be either the result of dereferencing the incremented iterator or the original iterator.
Prior to C++17, the situation was a bit complicated:
if both ++ and * invoke a function (e.g., when the type of it is a sophisticated class), then the behavior was unspecified, similar to the case since C++17;
otherwise, the behavior was undefined.
Per N4140 (C++14 draft) [expr.call]/8:
[ Note: The evaluations of the postfix expression and of the
arguments are all unsequenced relative to one another. All side
effects of argument evaluations are sequenced before the function is
entered (see [intro.execution]). — end note ]
Thus, the code was undefined behavior because the evaluation of one argument was unsequenced with the other. The evaluation of the two arguments may overlap, resulting in a data race. Unless it is specified otherwise ...
Per N4140 [intro.execution]/15:
When calling a function (whether or not the function is inline), every
value computation and side effect associated with any argument
expression, or with the postfix expression designating the called
function, is sequenced before execution of every expression or
statement in the body of the called function. [ Note: Value
computations and side effects associated with different argument
expressions are unsequenced. — end note ] Every evaluation
in the calling function (including other function calls) that is not
otherwise specifically sequenced before or after the execution of the
body of the called function is indeterminately sequenced with respect
to the execution of the called function.9 Several
contexts in C++ cause evaluation of a function call, even though no
corresponding function call syntax appears in the translation unit.
[
Example: Evaluation of a new expression invokes one or more allocation and constructor functions; see [expr.new]. For another
example, invocation of a conversion function ([class.conv.fct]) can
arise in contexts in which no function call syntax appears. —
end example ] The sequencing constraints on the execution of the called function (as described above) are features of the function
calls as evaluated, whatever the syntax of the expression that calls
the function might be.
9)
In other words, function executions do not interleave with each
other.
Thus, if the operators are actually function calls, then the behavior is similarly unspecified.
I have misunderstandingn on sec. 3.6.3/1 N3797. When I considered initialization rule I come across with copy-initialization concept.
If the completion of the constructor
or dynamic initialization of an object with static storage duration is
sequenced before that of another, the completion of the destructor of
the second is sequenced before the initiation of the destructor of the
first. [ Note: This definition permits concurrent destruction.— end
note ]
Is it possible that completion destructors of the second and of the first are in different threads?
Note: I edited and corrected the statement about unsequenced initialization (thanks to #dyp). If your program doesn't start any threads, then all initializations happen in some (possibly indeterminate) sequence.
There are no constraints beyond the constraints described in the Standard1 on which threads perform initialization and destruction of objects with static storage duration. In particular, the initialization of objects in different translation units are indeterminately sequenced with respect to one another (cf. [basic.start.init]/2), and unsequenced if the program starts threads.
It is therefore possible for initializations to occur concurrently in multiple threads if the first function call within a TU occurs within another thread other than the main thread. What the standard says is that those objects whose initialization is sequenced (e.g. those in the same TU) are also destroyed in a deterministic, compatible order.
______________
1) "beyond what is said, nothing is said" — a bit it of a tautology, but worth calling out
The C++98 language standard states:
(My emphasis)
3.6.2 Initialization of nonlocal objects
£1
[...]
Zeroinitialization
and initialization with a constant expression are collectively
called static initialization; all other initialization is dynamic initialization.
[...]
£3
[...]
It is implementationdefined
whether or not the dynamic initialization (8.5, 9.4, 12.1, 12.6.1) of an object of namespace scope is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first use of any function or object defined in the same translation unit as the object to be initialized.
[...]
In my office, we have got two interpretations of the boldface passage...
My question is: There is a class has a whole bunch of static methods and dynamically initialized static data members. Can it (or can't it) happen that static methods in this class are called from another translation unit, before dynamic initialization has been completed?
Thanks!
[Edit:]
Perhaps this boils down to the reading of "it shall occur" as:
Shall have begun
Shall have been completed
Can it (or can't it) happen that static methods in this class are called from another translation unit, before dynamic initialization has been completed?
The bolded passage is pretty clear, isn't it?
Initialization of such data is guaranteed to happen before first use of any function or class defined in its translation unit. It doesn't matter where a function is called from. The guarantee is that initialization happens before the first use of any functions in the translation unit. Of course they may be called from another translation unit, but that doesn't make any difference. Before a function defined in this translation unit is entered, initialization must have been performed.
In other words, you're safe.
...
assuming single-threaded execution, that is. C++98 provides no guarantees in a multithreaded environment, so for a threaded application, the above guarantee typically just means that initialization will be performed by the first thread to use a function or class from this translation unit. And then you have a race condition while this initialization is being performed, where other threads might hit the partially-initialized data.
I am very much trilled with the how a scoped_lock works and was wondering weather a similar implementation can be done as to time a particular code of execution
If say I implement a simple class scoped_timer which on construction initiates a timer and on deletion it stops and report the time elapsed, then would this sample code be timed correctly
func()
{
//some code
{
scoped_timer a;
//some code that does not include a
}
//some code
}
In practice am I guaranteed that scoped_time a is constructed at the beginning and destructed exactly when it is out of scope. Can the compiler decide to reorder the code in such a way as not to destruct it exactly at the end of scope or construct it at the beginning since there is no dependence on the object a? Are there guarantees from C++ standard?
Thanks
Daniel
The code is guaranteed to behave as you would like.
This guarantee is important in C++, because C++ is not a functional programming language, due to the fact that almost any function in C++ can have side effects (either from the flow of execution of the current thread, or from other threads or even other processes, whether or not the data is declared as volatile). Because of this, the language specification makes guarantees about the sequencing of full expressions.
To piece this together from the C++11 standard, there are a number of clauses that must be considered together.
The most important clause is §1.9:
§1.9 Program execution [intro.execution]
1 The semantic descriptions in this International Standard define a
parameterized nondeterministic abstract machine. This International
Standard places no requirement on the structure of conforming
implementations. In particular, they need not copy or emulate the
structure of the abstract machine. Rather, conforming implementations
are required to emulate (only) the observable behavior of the abstract
machine as explained below. * (<-- the footnote is in the standard itself)
* This provision is sometimes called the “as-if” rule, because an implementation is free to disregard any requirement of this
International Standard as long as the result is as if the requirement
had been obeyed, as far as can be determined from the observable
behavior of the program. For instance, an actual implementation need
not evaluate part of an expression if it can deduce that its value is
not used and that no side effects affecting the observable behavior of
the program are produced.
(The bolding of the text is mine.)
This clause imposes two important requirements that are relevant for this question.
If an expression may have side effects, it will be evaluated. In your case, the expression scoped_timer a; may have side effects, so it will be evaluated.
"...conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.", where "below" includes Clauses 13 and 14 of the same section:
§1.9.13 Sequenced before is an asymmetric, transitive, pair-wise
relation between evaluations executed by a single thread (1.10), which
induces a partial order among those evaluations. Given any two
evaluations A and B, if A is sequenced before B, then the execution of
A shall precede the execution of B. If A is not sequenced before B and
B is not sequenced before A, then A and B are unsequenced. [ Note: The
execution of unsequenced evaluations can overlap. —end note ]
Evaluations A and B are indeterminately sequenced when either A is
sequenced before B or B is sequenced before A, but it is unspecified
which. [ Note: Indeterminately sequenced evaluations cannot overlap,
but either could be executed first. —end note ]
§1.9.14 Every value computation and side effect associated with a
full-expression is sequenced before every value computation and side
effect associated with the next full-expression to be evaluated. * (<-- the footnote here is not relevant)
Therefore, your expression scoped_timer a; (which is a full expression) may have side effects and will be evaluated; so the computation of the value of a will be sequenced before any of the following statements in the block.
Regarding destruction of the object a, that is simpler.
§3.7.3.3 If a variable with automatic storage duration has initialization or a destructor with side effects, it shall not be
destroyed before the end of its block, nor shall it be eliminated as
an optimization even if it appears to be unused, except that a class
object or its copy/move may be eliminated as specified in 12.8.
This makes clear that the destructor will not be called until the block exits.
ADDENDUM And to confirm that all block-level variables are destroyed (and their destructor called) at the end of block scope, here it is in the C++11 standard:
§3.7.3.1 Block-scope variables explicitly declared register or not explicitly declared static or extern have automatic storage duration.
The storage for these entities lasts until the block in which they are
created exits.
§3.7.3.2 [ Note: These variables are initialized and destroyed as described in 6.7. —end note ]
... and the above-mentioned §6.7:
§6.7.2 Variables with automatic storage duration (3.7.3) are initialized each time their declaration-statement is executed.
Variables with automatic storage duration declared in the block are
destroyed on exit from the block (6.6).
The block is defined as all code between a pair of curly braces {} here:
§6.3.1 So that several statements can be used where one is expected, the compound statement (also, and equivalently, called “block”) is provided.
compound-statement:
{ statement-seq }
statement-seq:
statement
statement-seq statement
A compound statement defines a block scope (3.3).
Note: The compount-statement (etc) section takes a while to get used to, but the important point is that here, the open curly brace { and close curly brace } actually mean a literal open curly brace and close curly brace in the code. This is the exact place in the C++11 standard where block scope is defined as the sequence of statements between curly braces.
Putting the pieces together: Because the standard, as quoted above, says The storage for these entities lasts until the block in which they are created exits and that Variables with automatic storage duration declared in the block are destroyed on exit from the block, you are assured that the object a in your question (and ANY block-level object) will last until the end of the block, and will be destroyed and have its destructor called when the block exits.
At the top of some file in my program, outside all functions, I have these variables:
namespace {
int foo = foo_func();
}
int bar = bar_func();
As you know, foo is a variable local only to that file, but bar is accessible to every file.
...but question: When are the functions foo_func() and bar_func() actually run? Does this happen before main() runs, or possibly sometime later (say just before those values are actually needed)?
The language specification states that the initializing functions will be executed before any function from that translation unit is called or any object defined in that translation unit is accessed. So, in general case it really depends on how your definitions are spread across translation units.
The initialization is carried out in top-to-bottom order, so, given your order of definitions, bar_func should see already initialized foo, but foo_func should see "uninitialized" (i.e. zero-initialized) bar.
Note, that if your main resides in another translation unit, it means that the initialization does not have to happen before main(). Yet, if you attempt to access foo or bar from main (or from anywhere else), that should guarantee that the initialization process is triggered for the entire translation unit that defined these variables.
Also, if your initializers are constant expressions (constexpr functions), then the whole initialization can be performed statically, which typically means that the variables will begin their lifetimes in already initialized (compile-time initialized) states.
Initializing with the return value from a non-constexpr function is dynamic initialization. Order of dynamic initialization is defined as follows (leaving out some details I think are irrelevant to your question):
§3.6.2/2:
Variables with static storage duration (3.7.1) or thread storage duration (3.7.2) shall be zero-initialized (8.5) before any other initialization takes place.
[...]
Variables with ordered initialization defined within a single translation unit shall be initialized in the order of their definitions in the translation unit. If a program starts a thread (30.3), the subsequent initialization of a variable is unsequenced with respect to the initialization of a variable defined in a different translation unit. Otherwise, the initialization of a variable is indeterminately sequenced with respect to the initialization of a variable defined in a different translation unit.
§3.6.2/3:
An implementation is permitted to perform the initialization of a non-local variable with static storage duration as a static initialization even if such initialization is not required to be done statically, provided that [Jerry's summary: it produces the same result as if it had been done dynamically.]
§3.6.2/4:
It is implementation-defined whether the dynamic initialization of a non-local variable with static storage duration is done before the first statement of main. If the initialization is deferred to some point in time after the first statement of main, it shall occur before the first odr-use (3.2) of any function or variable defined in the same translation unit as the variable to be initialized