关于C++0x内存模型和序列点的一些思考
来源:互联网 发布:c语言位运算符号 编辑:程序博客网 时间:2024/05/21 04:23
Several questions about sequence point and concurrent memory model. (mostly focused on N2052)
1. When the standard says that the order of evaluation of arguments to a function is unspecified, does that mean they could be overlapped, or just indeterminately ordered?
This problem occurs to me when I was reading Boehm's memory model proposal [N2052], in which he suggested using "sequenced before" instead of "sequence point" and then stipulated the evaluation order of function arguments as "unsequenced", which explicitly allows overlapping according to his proposal.
So, my question is, are those two constraints (i.e. "unsequenced evaluation order" and "unspecified evaluation order") essentially equal? 'cause I was thinking that "unsequenced" is looser than "unspecified evaluation order".
I couldn't find any statement about whether or not an unspecified order allows overlapping in C++98. So, Could any one give an explanation please?
P.S. According to another statement of the evaluation order, which says "there's an sequence point after the evaluation of all the arguments and before the entry of the function", this obviously means that the value computation and side effect of the evaluations of the arguments could take place in any order, even overlapped (?), because there's no sequence point between them, right? So the implementation is free to rearrange the instructions.
Plus, according to my understanding of the sequence point, it doesn't really matter whether or not the evaluations of several sub-expressions between two adjacent sequence points (may we now say "not sequently related"?) could be overlapped, because it would be just a specification of the semantics of the abstract machine anyway. So even if the standard says that they should not be overlapped, a particular implementation can make them overlapped anyway, because "If a side effect on a scalar object is not sequenced relative to either a different side effect on the same scalar object, or a value computation using the value of the same scalar object, the behavior is undefined. [Excerpt from N2052]" which guarantees that overlapped evaluation of the arguments doesn't really change anything.
The sentence quoted above, according to my understanding, is very important, it essentially says that we can view all the value computations between two adjacent sequence points as operating on immutable variables because otherwise the program will have undefined behavior (e.g. a store operation on some variable used by a value computation would break the rule). And now that they operate on immutable variables, we can execute them disorderly, unsequencedly, overlappingly, or whatever, right?
2. Another question of which I want to make sure my judgment is right; the following call has undefined behavior, right?
f(i,i++); // undefined behavior.
3. There's a somewhat confusing example in N2052, see below:
x++ + increment_x(); // Evaluation order unspecified; x may be incremented only once
How could x be incremented only once when there’re obviously two "++"s. The only way that can happen is one of the two "++"s is thrown away.
I guess what the example really wants to say is that "the value of x may be x+1 instead of x+2", since the compiler could rearrange the execution order like this:
#assuming x originally is 1
load x into some register say r1 ( here we have r1==1) // the first 1/3 of evaluating x++, the left operand of operator +
increment_x() // this makes the value of x 2, here we have completed the evaluation of the right operand of operator +
store r1+1 to the memory location of x // this makes the value of x r1+1, which is 2! not 3.
return r1 as the value computation of the left operand of "+" // we got 1
as a last step, the evaluation of "+" is done here, which gives a value of 2, which perhaps lots of people assume not.
While we are done, we can see that the value of x is 2, not 3!
So, while the exact words, I think, should be "x is incremented twice but the final value of x is the value of original x plus 1 so that it's SEEMINGLY incremented once", of course we could say x is incremented just once, because the result equals x+1, but that would be confusing and misleading, at least at first to me (coz I was all "how in the name of god is that going to happen?":-) ). So I suggest clarifying this example by giving more detailed explanation, after all it's a pretty important example, right?
And since we are on that, there's a tiny typo in the definition of increment_x():
int increment_x() { x++; } // here we dropped a "return".
Plus, should "x++ + increment_x();" have undefined behavior according to the rule: "If a side effect on a scalar object is not sequenced relative to either a different side effect on the same scalar object, or a value computation using the value of the same scalar object, the behavior is undefined"?
4. If C++98 means overlap-able when it says unspecified evaluation order, then why Boehm, in N1944, says below:
[Excerpt from N1944]
Not every side effect or evaluation can be authoritatively determined to be either previous to or subsequent to a given sequence point. For example, given
a = 0;
b = (a = 1, 2*a) + 3*a;
The evaluation of “3*a” is not ordered with respect to the sequence point introduced by the comma operator. It may be previous or subsequent (NOTE HERE!!); the standard simply doesn't say. Therefore, that evaluation may or may not be separated from the assignment by a sequence point.
[End]
Why is it "It may be previous or subsequent"? If unspecified evaluation means "could overlap", then this should really be "It may be previous or subsequent, or overlapped with the sequence point introduced by the comma op." When I say "overlapped with", I mean like:
load a into some register say r1
(a=1, 2*a)
plus r1 by 3
...
That means the evaluation of "3*a" is _splitted_ by the sequence point introduced by the comma op.
Is this ordering allowed by the current standard (C++98)? If it is, then would it conflict with 1.9p7:
....called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place?
5. from clause 5 paragraph 4:
"Between the previous and next sequence point a scalar object shall ... ... .The requirements of this paragraph shall be met for each allowable ordering of the sub-expressions of a full expression; otherwise the behavior is undefined."
Here, what are these "allowable ordering of the sub-expressions"? According to my recollection, in no place has the current standard clearly stated which ordering is allowable and which is not. "Unspecified" is not clear enough to me, especially when it comes to whether or not it allows overlapping, which kind of is the core of all the questions I brought up here.
6. If unsequenced evaluation(overlapped execution, in particular) is allowed as said in N2052, would the evaluation of some simple expression give unpredictable value, which in turn makes the behavior undefined? Here's an example:
double d = ... ;
double g(double& d){ return d*=3.12; }
f( ++d, g(d) ); // should this be undefined behavior?
Now let's just say that we're on such an architecture that storing a double consists of storing its lower and higher DWORDs( if sizeof(double) equals that of a qword ) __separately__ . (coz it seems I have qword-level store instruction on my x86 pc)
So, on such an architecture, the instructions generated for the call to 'f' above would possibly be like this:
load d and compute d+1
store the lower dword of the result into the lower dword memory location of d, which now makes d half-baked.
evaluate g(d), which will use the half-baked d to compute d*3.12, and store that into d, making d into a unreasonable/ridiculous state
store the higher dword of the result computed beforehand by "++d" into the high dword memory location of d, which makes the value of d even more ridiculous.
call f
So, it seems this clearly should be categorized as undefined behavior, isn't it? But the real question is, which rule in the standard state clearly that this is undefined behavior, or instead, which rule in N2052 did? Plus, if the behavior of this example is undefined, then the "x++ + increment_x(); " example in N2052 would have undefined behavior, too, right?
7. excerpt from N2052:
"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."
I think this is overconstrained, because it will make "++d" indeterminately sequenced with respect to "g(d)" in "f( ++d, g(d) );"(see the example above), while actually they're supposed to be unsequenced. (if "f( ++d, g(d) );" is not clear enough, how about "++d + g(d);" ?)
But I'm not quite sure about this, so correct me if I made any stupid mistake.
I need clear answers to these questions, every single one, please, because the memory model is really driving me crazy these days :-)
Again, any help would be greatly appreciated, thanks you guys!
- 关于C++0x内存模型和序列点的一些思考
- 关于C++0x内存模型和序列点的一些思考
- 关于C++0x内存模型和序列点的一些思考
- 关于C++0x内存模型和序列点的一些思考
- 关于C++0x内存模型和序列点的一些思考
- 关于C++0x内存模型和序列点的一些思考
- 关于序列点的思考
- 初学者关于Objective-C 内存管理的几点思考
- 关于矩阵变换器的一些思考点
- 关于恶意经销商模型的一些思考
- 聊聊序列化(一)关于序列化协议的一些思考和问题
- .NET:关于数据模型、领域模型和视图模型的一些思考
- 关于Java内存溢出的一些思考
- 关于C语言的副作用和序列点~
- 关于序列化Serializable的几点思考
- 关于java与C的一些思考
- 关于Java框架Vert.x的几点思考
- 关于字典转模型的一些思考(持续更新中)
- Beautiful Proof - Data-Race-Free Implies Sequential Consistency铪铪
- 《Working Effectively With Legacy Code》译序
- Intuition out of counter-intuition
- 管理观点系列:团队管理
- C++0x简讯
- 关于C++0x内存模型和序列点的一些思考
- How Does it End()?
- .net面试题9
- Track'em Down铪铪铪铪铪铪铪
- 汉诺塔
- C++0x展望[语言核心进化]
- 锁无关的数据结构与Hazard指针——操纵有限的资源
- 锁无关的(Lock-Free)数据结构——在避免死锁的同时确保线程继续
- C++中的求值|副作用|序列点所导致的模糊语义