Correctness of 'Concurrency in Action' atomic operation example
I've been studing 'Concurency in Action' position for some time and I have a problem with understanding following example of code (Listing 5.2):
#include <vector>
#include <atomic>
#include <iostream>
std::vector<int> data;
std::atomic<bool> data_ready(false);
void reader_thread()
{
while(!data_ready.load())
{
std::this_thread::sleep(std::milliseconds(1));
}
std::cout<<”The answer=”<<data[0]<<”n”;
}
void writer_thread()
{
data.push_back(42); //write of data
data_ready=true; //write to data_ready flag
}
The book explaines:
(...) The write of the data happens-before the write to the data_ready
flag (...)
My concern is that the sentence does not cover the out-of-order execution. From my understanding out of order execution may happen when at least two instruction do not have depended operands. Taking this into account:
data_ready=true
does not need anything from
data.push_back(42)
to be executed. As a result of that it is not guaranteed that:
The write of the data happens-before the write to the data_ready flag
Is my understadning correct or there is something in out-of-order execution that I don't understand causing misunderstaning of given example?
EDIT
Thank you for answers, it was helpful. My misunserstanding was a result of not knowing that atomic types not only prevents from partialy channing a variable, but also acts as memory barrier.
For example following code may be reordered in many combinations by either compiler or processor:
d=0;
b=5;
a=10
c=1;
Resulting with following order (one of many possibilities):
b=5;
a=10
c=1;
d=0;
It it is not a problem with single-thread code since none of expressions have depended operands on other, but on multithreaded application may result of undefined behaviour. For example following code (initial values: x=0 and y=0):
Thread 1: Thread 2:
x=10; while(y!=15);
y=15; assert(x==10);
Without reordering of code by compiler or reordering execution by processor we could say: "Since assigement y=15 allways happens after assigement x=10 and assert happens after while loop the assert will never fail" But it's not true. The real execution order may be as below (one of many possible combinations):
Thread 1: Thread 2:
x=10; (4) while(y!=15); (3)
y=15; (1) assert(x==10); (2)
By default an atomic variable ensures sequentionally consistent ordering. If y in example above was atomic with memory_order_seq_cst default parameter following sentences are true:
- what happens before in thread 1 (x=10
) it is also visible in thread 2 as happening before.
- what happens after while(y!=15)
in thread 2 it is also visible in thread 1 as happening after
As a result of it assert will never fail.
Some of sources that may help with understaning:
- Memory model synchronization modes - GCC
- CppCon 2015: Michael Wong “C++11/14/17 atomics and memory
model..." - Memory barriers in C
c++ multithreading atomic
add a comment |
I've been studing 'Concurency in Action' position for some time and I have a problem with understanding following example of code (Listing 5.2):
#include <vector>
#include <atomic>
#include <iostream>
std::vector<int> data;
std::atomic<bool> data_ready(false);
void reader_thread()
{
while(!data_ready.load())
{
std::this_thread::sleep(std::milliseconds(1));
}
std::cout<<”The answer=”<<data[0]<<”n”;
}
void writer_thread()
{
data.push_back(42); //write of data
data_ready=true; //write to data_ready flag
}
The book explaines:
(...) The write of the data happens-before the write to the data_ready
flag (...)
My concern is that the sentence does not cover the out-of-order execution. From my understanding out of order execution may happen when at least two instruction do not have depended operands. Taking this into account:
data_ready=true
does not need anything from
data.push_back(42)
to be executed. As a result of that it is not guaranteed that:
The write of the data happens-before the write to the data_ready flag
Is my understadning correct or there is something in out-of-order execution that I don't understand causing misunderstaning of given example?
EDIT
Thank you for answers, it was helpful. My misunserstanding was a result of not knowing that atomic types not only prevents from partialy channing a variable, but also acts as memory barrier.
For example following code may be reordered in many combinations by either compiler or processor:
d=0;
b=5;
a=10
c=1;
Resulting with following order (one of many possibilities):
b=5;
a=10
c=1;
d=0;
It it is not a problem with single-thread code since none of expressions have depended operands on other, but on multithreaded application may result of undefined behaviour. For example following code (initial values: x=0 and y=0):
Thread 1: Thread 2:
x=10; while(y!=15);
y=15; assert(x==10);
Without reordering of code by compiler or reordering execution by processor we could say: "Since assigement y=15 allways happens after assigement x=10 and assert happens after while loop the assert will never fail" But it's not true. The real execution order may be as below (one of many possible combinations):
Thread 1: Thread 2:
x=10; (4) while(y!=15); (3)
y=15; (1) assert(x==10); (2)
By default an atomic variable ensures sequentionally consistent ordering. If y in example above was atomic with memory_order_seq_cst default parameter following sentences are true:
- what happens before in thread 1 (x=10
) it is also visible in thread 2 as happening before.
- what happens after while(y!=15)
in thread 2 it is also visible in thread 1 as happening after
As a result of it assert will never fail.
Some of sources that may help with understaning:
- Memory model synchronization modes - GCC
- CppCon 2015: Michael Wong “C++11/14/17 atomics and memory
model..." - Memory barriers in C
c++ multithreading atomic
Possible duplicate of what and how does happens-before happen in c++0x
– Tsyvarev
Dec 29 '18 at 13:35
add a comment |
I've been studing 'Concurency in Action' position for some time and I have a problem with understanding following example of code (Listing 5.2):
#include <vector>
#include <atomic>
#include <iostream>
std::vector<int> data;
std::atomic<bool> data_ready(false);
void reader_thread()
{
while(!data_ready.load())
{
std::this_thread::sleep(std::milliseconds(1));
}
std::cout<<”The answer=”<<data[0]<<”n”;
}
void writer_thread()
{
data.push_back(42); //write of data
data_ready=true; //write to data_ready flag
}
The book explaines:
(...) The write of the data happens-before the write to the data_ready
flag (...)
My concern is that the sentence does not cover the out-of-order execution. From my understanding out of order execution may happen when at least two instruction do not have depended operands. Taking this into account:
data_ready=true
does not need anything from
data.push_back(42)
to be executed. As a result of that it is not guaranteed that:
The write of the data happens-before the write to the data_ready flag
Is my understadning correct or there is something in out-of-order execution that I don't understand causing misunderstaning of given example?
EDIT
Thank you for answers, it was helpful. My misunserstanding was a result of not knowing that atomic types not only prevents from partialy channing a variable, but also acts as memory barrier.
For example following code may be reordered in many combinations by either compiler or processor:
d=0;
b=5;
a=10
c=1;
Resulting with following order (one of many possibilities):
b=5;
a=10
c=1;
d=0;
It it is not a problem with single-thread code since none of expressions have depended operands on other, but on multithreaded application may result of undefined behaviour. For example following code (initial values: x=0 and y=0):
Thread 1: Thread 2:
x=10; while(y!=15);
y=15; assert(x==10);
Without reordering of code by compiler or reordering execution by processor we could say: "Since assigement y=15 allways happens after assigement x=10 and assert happens after while loop the assert will never fail" But it's not true. The real execution order may be as below (one of many possible combinations):
Thread 1: Thread 2:
x=10; (4) while(y!=15); (3)
y=15; (1) assert(x==10); (2)
By default an atomic variable ensures sequentionally consistent ordering. If y in example above was atomic with memory_order_seq_cst default parameter following sentences are true:
- what happens before in thread 1 (x=10
) it is also visible in thread 2 as happening before.
- what happens after while(y!=15)
in thread 2 it is also visible in thread 1 as happening after
As a result of it assert will never fail.
Some of sources that may help with understaning:
- Memory model synchronization modes - GCC
- CppCon 2015: Michael Wong “C++11/14/17 atomics and memory
model..." - Memory barriers in C
c++ multithreading atomic
I've been studing 'Concurency in Action' position for some time and I have a problem with understanding following example of code (Listing 5.2):
#include <vector>
#include <atomic>
#include <iostream>
std::vector<int> data;
std::atomic<bool> data_ready(false);
void reader_thread()
{
while(!data_ready.load())
{
std::this_thread::sleep(std::milliseconds(1));
}
std::cout<<”The answer=”<<data[0]<<”n”;
}
void writer_thread()
{
data.push_back(42); //write of data
data_ready=true; //write to data_ready flag
}
The book explaines:
(...) The write of the data happens-before the write to the data_ready
flag (...)
My concern is that the sentence does not cover the out-of-order execution. From my understanding out of order execution may happen when at least two instruction do not have depended operands. Taking this into account:
data_ready=true
does not need anything from
data.push_back(42)
to be executed. As a result of that it is not guaranteed that:
The write of the data happens-before the write to the data_ready flag
Is my understadning correct or there is something in out-of-order execution that I don't understand causing misunderstaning of given example?
EDIT
Thank you for answers, it was helpful. My misunserstanding was a result of not knowing that atomic types not only prevents from partialy channing a variable, but also acts as memory barrier.
For example following code may be reordered in many combinations by either compiler or processor:
d=0;
b=5;
a=10
c=1;
Resulting with following order (one of many possibilities):
b=5;
a=10
c=1;
d=0;
It it is not a problem with single-thread code since none of expressions have depended operands on other, but on multithreaded application may result of undefined behaviour. For example following code (initial values: x=0 and y=0):
Thread 1: Thread 2:
x=10; while(y!=15);
y=15; assert(x==10);
Without reordering of code by compiler or reordering execution by processor we could say: "Since assigement y=15 allways happens after assigement x=10 and assert happens after while loop the assert will never fail" But it's not true. The real execution order may be as below (one of many possible combinations):
Thread 1: Thread 2:
x=10; (4) while(y!=15); (3)
y=15; (1) assert(x==10); (2)
By default an atomic variable ensures sequentionally consistent ordering. If y in example above was atomic with memory_order_seq_cst default parameter following sentences are true:
- what happens before in thread 1 (x=10
) it is also visible in thread 2 as happening before.
- what happens after while(y!=15)
in thread 2 it is also visible in thread 1 as happening after
As a result of it assert will never fail.
Some of sources that may help with understaning:
- Memory model synchronization modes - GCC
- CppCon 2015: Michael Wong “C++11/14/17 atomics and memory
model..." - Memory barriers in C
c++ multithreading atomic
c++ multithreading atomic
edited Dec 30 '18 at 11:17
Adam Stepniak
asked Dec 29 '18 at 13:13
Adam StepniakAdam Stepniak
17419
17419
Possible duplicate of what and how does happens-before happen in c++0x
– Tsyvarev
Dec 29 '18 at 13:35
add a comment |
Possible duplicate of what and how does happens-before happen in c++0x
– Tsyvarev
Dec 29 '18 at 13:35
Possible duplicate of what and how does happens-before happen in c++0x
– Tsyvarev
Dec 29 '18 at 13:35
Possible duplicate of what and how does happens-before happen in c++0x
– Tsyvarev
Dec 29 '18 at 13:35
add a comment |
2 Answers
2
active
oldest
votes
I understand your concerns, but the code from book is fine. Every operation with atomics is by default memory_order_seq_cst
, which means that everything that happened before the write in one of threads happens before read in the rest. You can imagine atomic operations with this std::memory_order
like this:
std::atomic<bool> a;
//equivalent of a = true
a.assign_and_make_changes_from_thread_visible(true);
//equvalent of a.load()
a.get_value_and_changes_from_threads();
add a comment |
From Effective Modern C++, Item 40, it says "std::atomics imposes restrictions on how code can be reordered, and one such restriction is that no code that, in the source cod, precedes a write of std::atomic variable may take place afterwards." The note is this is true for when using sequential consistency which is a fair assumption.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53969879%2fcorrectness-of-concurrency-in-action-atomic-operation-example%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
I understand your concerns, but the code from book is fine. Every operation with atomics is by default memory_order_seq_cst
, which means that everything that happened before the write in one of threads happens before read in the rest. You can imagine atomic operations with this std::memory_order
like this:
std::atomic<bool> a;
//equivalent of a = true
a.assign_and_make_changes_from_thread_visible(true);
//equvalent of a.load()
a.get_value_and_changes_from_threads();
add a comment |
I understand your concerns, but the code from book is fine. Every operation with atomics is by default memory_order_seq_cst
, which means that everything that happened before the write in one of threads happens before read in the rest. You can imagine atomic operations with this std::memory_order
like this:
std::atomic<bool> a;
//equivalent of a = true
a.assign_and_make_changes_from_thread_visible(true);
//equvalent of a.load()
a.get_value_and_changes_from_threads();
add a comment |
I understand your concerns, but the code from book is fine. Every operation with atomics is by default memory_order_seq_cst
, which means that everything that happened before the write in one of threads happens before read in the rest. You can imagine atomic operations with this std::memory_order
like this:
std::atomic<bool> a;
//equivalent of a = true
a.assign_and_make_changes_from_thread_visible(true);
//equvalent of a.load()
a.get_value_and_changes_from_threads();
I understand your concerns, but the code from book is fine. Every operation with atomics is by default memory_order_seq_cst
, which means that everything that happened before the write in one of threads happens before read in the rest. You can imagine atomic operations with this std::memory_order
like this:
std::atomic<bool> a;
//equivalent of a = true
a.assign_and_make_changes_from_thread_visible(true);
//equvalent of a.load()
a.get_value_and_changes_from_threads();
answered Dec 29 '18 at 13:20


bartopbartop
2,855826
2,855826
add a comment |
add a comment |
From Effective Modern C++, Item 40, it says "std::atomics imposes restrictions on how code can be reordered, and one such restriction is that no code that, in the source cod, precedes a write of std::atomic variable may take place afterwards." The note is this is true for when using sequential consistency which is a fair assumption.
add a comment |
From Effective Modern C++, Item 40, it says "std::atomics imposes restrictions on how code can be reordered, and one such restriction is that no code that, in the source cod, precedes a write of std::atomic variable may take place afterwards." The note is this is true for when using sequential consistency which is a fair assumption.
add a comment |
From Effective Modern C++, Item 40, it says "std::atomics imposes restrictions on how code can be reordered, and one such restriction is that no code that, in the source cod, precedes a write of std::atomic variable may take place afterwards." The note is this is true for when using sequential consistency which is a fair assumption.
From Effective Modern C++, Item 40, it says "std::atomics imposes restrictions on how code can be reordered, and one such restriction is that no code that, in the source cod, precedes a write of std::atomic variable may take place afterwards." The note is this is true for when using sequential consistency which is a fair assumption.
answered Dec 29 '18 at 13:22
Eddie C.Eddie C.
387
387
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53969879%2fcorrectness-of-concurrency-in-action-atomic-operation-example%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Possible duplicate of what and how does happens-before happen in c++0x
– Tsyvarev
Dec 29 '18 at 13:35