Interoperabilty between C and C++ atomics
Suppose, I have a task that might be cancelled from another thread. The task is performed in a C function, another thread runs C++ code. How do I do that?
Rough example.
C:
void do_task(atomic_bool const *cancelled);
C++:
std::atomic_bool cancelled;
…
do_task(&cancelled);
For now, I created a file atomics.h
with the following content:
#ifdef __cplusplus
#include <atomic>
using std::atomic_bool;
#else
#include <stdatomic.h>
#endif
It appears to work, but I don't see any guarantees for that. I wonder, if there is a better (correct) way.
c++ c atomic
|
show 6 more comments
Suppose, I have a task that might be cancelled from another thread. The task is performed in a C function, another thread runs C++ code. How do I do that?
Rough example.
C:
void do_task(atomic_bool const *cancelled);
C++:
std::atomic_bool cancelled;
…
do_task(&cancelled);
For now, I created a file atomics.h
with the following content:
#ifdef __cplusplus
#include <atomic>
using std::atomic_bool;
#else
#include <stdatomic.h>
#endif
It appears to work, but I don't see any guarantees for that. I wonder, if there is a better (correct) way.
c++ c atomic
for what you here need atomic ? which operation need to be atomic ? nothing. you here need volatile by sense, but not atomic -void do_task(volatile bool *cancelled);
– RbMm
Dec 22 '18 at 21:47
really in most case you even not need volatile if inside loopdo { * } while (!*cancelled);
you call some external function, for which compiler can not know - are it modify*cancelled
– RbMm
Dec 22 '18 at 21:56
@RbMm: Advice to do things that might happen to work on current tooling but that is explicitly wrong and has no advantages over doing it right is not helpful.
– R..
Dec 23 '18 at 8:14
@R.. - why this is explicitly wrong ? of course without view complete code can not exactly say are need atomic here, but how usual cancelled use - not require any atomic or memory order other than relaxed. need only volatile.
– RbMm
Dec 23 '18 at 8:37
@RbMn one threads reads a variable. one thread writes it. all without further synchronization-> you need atomic. end of story.
– phön
Dec 23 '18 at 9:32
|
show 6 more comments
Suppose, I have a task that might be cancelled from another thread. The task is performed in a C function, another thread runs C++ code. How do I do that?
Rough example.
C:
void do_task(atomic_bool const *cancelled);
C++:
std::atomic_bool cancelled;
…
do_task(&cancelled);
For now, I created a file atomics.h
with the following content:
#ifdef __cplusplus
#include <atomic>
using std::atomic_bool;
#else
#include <stdatomic.h>
#endif
It appears to work, but I don't see any guarantees for that. I wonder, if there is a better (correct) way.
c++ c atomic
Suppose, I have a task that might be cancelled from another thread. The task is performed in a C function, another thread runs C++ code. How do I do that?
Rough example.
C:
void do_task(atomic_bool const *cancelled);
C++:
std::atomic_bool cancelled;
…
do_task(&cancelled);
For now, I created a file atomics.h
with the following content:
#ifdef __cplusplus
#include <atomic>
using std::atomic_bool;
#else
#include <stdatomic.h>
#endif
It appears to work, but I don't see any guarantees for that. I wonder, if there is a better (correct) way.
c++ c atomic
c++ c atomic
asked Dec 22 '18 at 18:50
grepcakegrepcake
6681520
6681520
for what you here need atomic ? which operation need to be atomic ? nothing. you here need volatile by sense, but not atomic -void do_task(volatile bool *cancelled);
– RbMm
Dec 22 '18 at 21:47
really in most case you even not need volatile if inside loopdo { * } while (!*cancelled);
you call some external function, for which compiler can not know - are it modify*cancelled
– RbMm
Dec 22 '18 at 21:56
@RbMm: Advice to do things that might happen to work on current tooling but that is explicitly wrong and has no advantages over doing it right is not helpful.
– R..
Dec 23 '18 at 8:14
@R.. - why this is explicitly wrong ? of course without view complete code can not exactly say are need atomic here, but how usual cancelled use - not require any atomic or memory order other than relaxed. need only volatile.
– RbMm
Dec 23 '18 at 8:37
@RbMn one threads reads a variable. one thread writes it. all without further synchronization-> you need atomic. end of story.
– phön
Dec 23 '18 at 9:32
|
show 6 more comments
for what you here need atomic ? which operation need to be atomic ? nothing. you here need volatile by sense, but not atomic -void do_task(volatile bool *cancelled);
– RbMm
Dec 22 '18 at 21:47
really in most case you even not need volatile if inside loopdo { * } while (!*cancelled);
you call some external function, for which compiler can not know - are it modify*cancelled
– RbMm
Dec 22 '18 at 21:56
@RbMm: Advice to do things that might happen to work on current tooling but that is explicitly wrong and has no advantages over doing it right is not helpful.
– R..
Dec 23 '18 at 8:14
@R.. - why this is explicitly wrong ? of course without view complete code can not exactly say are need atomic here, but how usual cancelled use - not require any atomic or memory order other than relaxed. need only volatile.
– RbMm
Dec 23 '18 at 8:37
@RbMn one threads reads a variable. one thread writes it. all without further synchronization-> you need atomic. end of story.
– phön
Dec 23 '18 at 9:32
for what you here need atomic ? which operation need to be atomic ? nothing. you here need volatile by sense, but not atomic -
void do_task(volatile bool *cancelled);
– RbMm
Dec 22 '18 at 21:47
for what you here need atomic ? which operation need to be atomic ? nothing. you here need volatile by sense, but not atomic -
void do_task(volatile bool *cancelled);
– RbMm
Dec 22 '18 at 21:47
really in most case you even not need volatile if inside loop
do { * } while (!*cancelled);
you call some external function, for which compiler can not know - are it modify *cancelled
– RbMm
Dec 22 '18 at 21:56
really in most case you even not need volatile if inside loop
do { * } while (!*cancelled);
you call some external function, for which compiler can not know - are it modify *cancelled
– RbMm
Dec 22 '18 at 21:56
@RbMm: Advice to do things that might happen to work on current tooling but that is explicitly wrong and has no advantages over doing it right is not helpful.
– R..
Dec 23 '18 at 8:14
@RbMm: Advice to do things that might happen to work on current tooling but that is explicitly wrong and has no advantages over doing it right is not helpful.
– R..
Dec 23 '18 at 8:14
@R.. - why this is explicitly wrong ? of course without view complete code can not exactly say are need atomic here, but how usual cancelled use - not require any atomic or memory order other than relaxed. need only volatile.
– RbMm
Dec 23 '18 at 8:37
@R.. - why this is explicitly wrong ? of course without view complete code can not exactly say are need atomic here, but how usual cancelled use - not require any atomic or memory order other than relaxed. need only volatile.
– RbMm
Dec 23 '18 at 8:37
@RbMn one threads reads a variable. one thread writes it. all without further synchronization-> you need atomic. end of story.
– phön
Dec 23 '18 at 9:32
@RbMn one threads reads a variable. one thread writes it. all without further synchronization-> you need atomic. end of story.
– phön
Dec 23 '18 at 9:32
|
show 6 more comments
5 Answers
5
active
oldest
votes
The atomic_bool
type in C and the std::atomic<bool>
type in C++ (typedefed as std::atomic_bool
) are two different types that are unrelated. Passing a std::atomic_bool
to a C function expecting C's atomic_bool
is Undefined Behavior. That it works at all is a combination of luck and the simple definitions of these types being compatible.
If the C++ code needs to call a C function that expects C's atomic_bool
, then that is what it must use. However, the <stdatomic.h>
header does not exist in C++. You'll have to provide a way for the C++ code to call C code to get a pointer to the atomic variable you need in a way that hides the type. (Possibly declare a struct that holds the atomic bool, that C++ would only know that the type exists and only know about pointers to it.)
It doesn't matter that they are different types. They basically synchronize the same byte of memory via same memory operations.struct A{int x; int y; int z};
andstruct B{int a[3];};
are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior. Same withatomic_bool
andstd::atomic<bool>
.
– ALX23z
Dec 22 '18 at 20:36
1
from developers.redhat.com/blog/2016/01/14/… "The atomic types are fully interoperable between the two languages so that programs can be developed that share objects of atomic types across the language boundary."
– Manny_Mar
Dec 22 '18 at 23:29
1
@ALX23z "are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior" Really?
– Lightness Races in Orbit
Dec 23 '18 at 1:25
@LightnessRacesinOrbit "Really?" Of course, from POV of CPU it is just 3 consecutive integers - 12 bytes of data. Who cares what you called these variables in your source code? Definitely not the program after you compiled it. Perhaps, 100 years into the future they will decide that compiler can rearrange internal variables in any order but it is not the case now or in any foreseeable future. Try and find system whereA a; B *b = (B*)(void*)&a;
won't work correctly.
– ALX23z
Dec 23 '18 at 2:19
3
@ALX23z: "from POV of CPU" doesn't matter. That's not how undefined behavior works.
– user2357112
Dec 23 '18 at 2:22
|
show 1 more comment
To side-step all ABI issues you may like to implement a C function that is called from C++ and operates on that atomic_bool
. This way your C++ code doesn't need to know anything about that global variable and its type:
In an .h
file:
#ifdef __cplusplus
extern "C" {
#endif
void cancel_my_thread(void);
int is_my_thread_cancelled(void);
#ifdef __cplusplus
}
#endif
And then in a .c
file:
#include <stdatomic.h>
static atomic_bool cancelled = 0;
void cancel_my_thread(void) {
atomic_store_explicit(&cancelled, 1, memory_order_relaxed);
}
int is_my_thread_cancelled(void) {
return atomic_load_explicit(&cancelled, memory_order_relaxed);
}
The C++ code would include that headed and call cancel_my_thread
.
Thank you, it is a sane solution, however in my particular case,do_task
might be called from several threads, so using using global variable wouldn't work. I guess, I'll just wrap it in a struct as @1201ProgramAlarm suggests.
– grepcake
Dec 23 '18 at 9:13
add a comment |
I found this on a net search https://developers.redhat.com/blog/2016/01/14/toward-a-better-use-of-c11-atomics-part-1/
Following the lead of C++, along with a memory model describing the
requirements and semantics of multithreaded programs, the C11 standard
adopted a proposal for a set of atomic types and operations into the
language. This change has made it possible to write portable
multi-threaded software that efficiently manipulates objects
indivisibly and without data races. The atomic types are fully
interoperable between the two languages so that programs can be
developed that share objects of atomic types across the language
boundary. This paper examines some of the trade-offs of the design,
points out some of its shortcomings, and outlines solutions that
simplify the use of atomic objects in both languages.
I am just learning about atomics now, but it looks like its compatible between C and CPP.
1
Do you have a more authoritative source than "some guy's blog said it was okay"?
– user2357112
Dec 23 '18 at 2:16
If you read it the paper is about trade-offs of the design, points out some of its shortcomings, and outlines solutions that simplify the use of atomic objects in both languages. He goes into a lot of detail, which I think require some knowledge. I do not claim to be an expert on this. I did read in the past, that C11 got it's atomics from cpp.
– Manny_Mar
Dec 23 '18 at 2:21
add a comment |
how i understand your code in general is (must be) next
// c code
void _do_task();
void do_task(volatile bool *cancelled)
{
do {
_do_task();
} while (!*cancelled);
}
// c++ code
volatile bool g_cancelled;// can be modify by another thread
do_task(&cancelled);
void some_proc()
{
//...
g_cancelled = true;
}
i be ask question - are here we need declare cancelled
as atomic ? are we need atomic here ?
atomic need in 3 case:
we do Read-Modify-Write operation. say if we need set
cancelled
to true and check are it was alreadytrue
. this for example can be need if several threads setcancelled
to true and who do this first need free some resources.
if (!cancelled.exchange(true)) { free_resources(); }
the read or write operation for type need to be atomic. of course on
all current and all possible future implementations this is true for
bool type (despite formal not defined). but even this is not
important. we here checkcancelled
only for 2 values - 0 (false
) and
all another. so even if both write and read operation on
cancelled assume not atomic, after one thread write non-zero to
canceled, another thread sooner or later will read modified non-zero value
fromcanceled
. even if it will be another value, not the same
first thread write: for example ifcancelled = true
translated to
mov cancelled, -1; mov cancelled, 1
- two hardware, not atomic
operation - second thread can read-1
instead final1
(true
)
from canceled, but this not play role if we check only for non-zero - all
another values break loop -while (!*cancelled);
if we use here atomic operation for write/readcancelled
- nothing change here - after one thread atomic write to it another thread sooner or later will read modified non-zero value from canceled - atomic operation or not - memory is common - if one thread write to memory (atomic or no) another threads sooner or later will view this memory modification.- we need synchronize another read/writes with cancelled. so we need
synchronization point between 2 threads aroundcanceled
with memory
order other thanmemory_order_relaxed
say for example next code:
//
void _do_task();
int result;
void do_task(atomic_bool *cancelled)
{
do {
_do_task();
} while (!g_cancelled.load(memory_order_acquire));
switch(result)
{
case 1:
//...
break;
}
}
void some_proc()
{
result = 1;
g_cancelled.store(true, memory_order_release);
}
so we not simply set g_cancelled
to true here, but before this
write some shared data (result
) and want that another thread after
view modification of g_cancelled, will be also view modification of
shared data (result
). but i doubt that you actually use/need this
scenario
if none of this 3 things is need- you not need atomic here. what you really need - that one thread just write true to cancelled
and another thread all time read value of cancelled
(instead do this once and cache result). usual in most case of code this will be done auto, but for be exactly you need declare canceled as volatile
if however you by some reason need exactly atomic (atomic_bool
), because you here cross the border of languages, you need understand concrete implementation of atomic_bool
in both languages and are it the same (type declaration, operations (load, store, etc)). by fact atomic_bool
is the same for c and c++.
or (better) instead of make visible and share type atomic_bool
use interface functions like
bool is_canceled(void* cancelled);
so code can be next
// c code
void _do_task();
bool is_canceled(void* cancelled);
void do_task(void *cancelled)
{
do {
_do_task();
} while (!is_canceled(cancelled));
}
// c++ code
atomic_bool g_cancelled;// can be modify by another thread
bool is_canceled(void* cancelled)
{
return *reinterpret_cast<atomic_bool*>(cancelled);
}
void some_proc()
{
//...
g_cancelled = true;
}
do_task(&g_cancelled);
but again i doubt that in your task you need atomic_bool
by semantic. you need volatile bool
add a comment |
Atomicity of operations is caused by hardware, not software (well, in C++ there are also "atomic" variables that are atomic in name only, those are implemented via mutexes and locks). So, basically, C++ atomics and C atomics do the very same thing. Hence as long as the types are compatible there won't be issues. And C++11 and C11 atomic classes were made to be compatible.
Apparently, people do not understand how atomics and locks work and require further explanation. Check out current memory models for more information.
1) We will start with basics. What and why are atomics? How does memory works?
Memory Model: think of processor as several independent cores and each has its own memory (cashes L1, L2, and L3; and in fact, L3 cash is common but it isn't really important).
Why do we need atomic operation?
If you don't use atomics, then each processor might have its own version of the variable 'x' and they are in general not synchronized. There is no telling when they will perform synchronizations with RAM/L3 cash.
When atomic operations are used, such memory operations are used that ensure synchronization with RAM/L3 cash (or whatever is needed) - ensuring that different cores have access to the same variable and not have variety of different versions of it.
Nobody cares if it is C, C++, or whatever language you use - as long as one ensures memory synchronization (both read, write, and modify) there will never be no issues.
2) OK, what about locks and mutexes?
Mutexes tend to work with OS and have queue over which thread should be allowed next to perform. And they enforce stricter memory synchronization than atomics do. With atomics one can syhchronize just the variable itself or more depending on the request / which function you call.
3) Say I have atomic_bool, can it work in interchangeably on different languages (C/C++11)?
Normally a boolean can be sychronized via memory operations (you're just synchronizing a single byte of memory from their perspective).
If the compilers are aware that the hardware can perform such operations then they surely will use them as long as you use the standard.
Logical atomics (any std::atomic< T > with T having wrong size/alignment) are synchronized via locks. In this case it is unlikely that different languages can use them interchangeably - if they have different methods of usage of these locks, or for some reason one decided to use a lock and the other one came to conclusion that it can work with atomic hardware memory synchronizations... then there will be issues.
If you use atomic_bool on any modern machine with C/C++, it will surely be able to synchronize without locks.
8
"And C++11 and C11 atomic classes were made to be compatible" Can you cite any source for this claim? Moreover, std::atomic_bool is not guaranteed to be lock free as opposed to std::atomic_flag.
– idmean
Dec 22 '18 at 19:12
@idmean atomic_bool is not guaranteed to be lock free by the standart, as it doesn't require it to be. Whether it is lock free or not is something you ought to ask hardware whether it supports atomic operations. Locks are also in sense atomics, as they force more strict memory syncronization, while atomics allow way more relaxed memory sync.
– ALX23z
Dec 22 '18 at 19:22
It reads like a rant by a newcomer who's mad that experts are telling them they're wrong.
– R..
Dec 23 '18 at 8:18
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%2f53898429%2finteroperabilty-between-c-and-c-atomics%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
The atomic_bool
type in C and the std::atomic<bool>
type in C++ (typedefed as std::atomic_bool
) are two different types that are unrelated. Passing a std::atomic_bool
to a C function expecting C's atomic_bool
is Undefined Behavior. That it works at all is a combination of luck and the simple definitions of these types being compatible.
If the C++ code needs to call a C function that expects C's atomic_bool
, then that is what it must use. However, the <stdatomic.h>
header does not exist in C++. You'll have to provide a way for the C++ code to call C code to get a pointer to the atomic variable you need in a way that hides the type. (Possibly declare a struct that holds the atomic bool, that C++ would only know that the type exists and only know about pointers to it.)
It doesn't matter that they are different types. They basically synchronize the same byte of memory via same memory operations.struct A{int x; int y; int z};
andstruct B{int a[3];};
are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior. Same withatomic_bool
andstd::atomic<bool>
.
– ALX23z
Dec 22 '18 at 20:36
1
from developers.redhat.com/blog/2016/01/14/… "The atomic types are fully interoperable between the two languages so that programs can be developed that share objects of atomic types across the language boundary."
– Manny_Mar
Dec 22 '18 at 23:29
1
@ALX23z "are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior" Really?
– Lightness Races in Orbit
Dec 23 '18 at 1:25
@LightnessRacesinOrbit "Really?" Of course, from POV of CPU it is just 3 consecutive integers - 12 bytes of data. Who cares what you called these variables in your source code? Definitely not the program after you compiled it. Perhaps, 100 years into the future they will decide that compiler can rearrange internal variables in any order but it is not the case now or in any foreseeable future. Try and find system whereA a; B *b = (B*)(void*)&a;
won't work correctly.
– ALX23z
Dec 23 '18 at 2:19
3
@ALX23z: "from POV of CPU" doesn't matter. That's not how undefined behavior works.
– user2357112
Dec 23 '18 at 2:22
|
show 1 more comment
The atomic_bool
type in C and the std::atomic<bool>
type in C++ (typedefed as std::atomic_bool
) are two different types that are unrelated. Passing a std::atomic_bool
to a C function expecting C's atomic_bool
is Undefined Behavior. That it works at all is a combination of luck and the simple definitions of these types being compatible.
If the C++ code needs to call a C function that expects C's atomic_bool
, then that is what it must use. However, the <stdatomic.h>
header does not exist in C++. You'll have to provide a way for the C++ code to call C code to get a pointer to the atomic variable you need in a way that hides the type. (Possibly declare a struct that holds the atomic bool, that C++ would only know that the type exists and only know about pointers to it.)
It doesn't matter that they are different types. They basically synchronize the same byte of memory via same memory operations.struct A{int x; int y; int z};
andstruct B{int a[3];};
are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior. Same withatomic_bool
andstd::atomic<bool>
.
– ALX23z
Dec 22 '18 at 20:36
1
from developers.redhat.com/blog/2016/01/14/… "The atomic types are fully interoperable between the two languages so that programs can be developed that share objects of atomic types across the language boundary."
– Manny_Mar
Dec 22 '18 at 23:29
1
@ALX23z "are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior" Really?
– Lightness Races in Orbit
Dec 23 '18 at 1:25
@LightnessRacesinOrbit "Really?" Of course, from POV of CPU it is just 3 consecutive integers - 12 bytes of data. Who cares what you called these variables in your source code? Definitely not the program after you compiled it. Perhaps, 100 years into the future they will decide that compiler can rearrange internal variables in any order but it is not the case now or in any foreseeable future. Try and find system whereA a; B *b = (B*)(void*)&a;
won't work correctly.
– ALX23z
Dec 23 '18 at 2:19
3
@ALX23z: "from POV of CPU" doesn't matter. That's not how undefined behavior works.
– user2357112
Dec 23 '18 at 2:22
|
show 1 more comment
The atomic_bool
type in C and the std::atomic<bool>
type in C++ (typedefed as std::atomic_bool
) are two different types that are unrelated. Passing a std::atomic_bool
to a C function expecting C's atomic_bool
is Undefined Behavior. That it works at all is a combination of luck and the simple definitions of these types being compatible.
If the C++ code needs to call a C function that expects C's atomic_bool
, then that is what it must use. However, the <stdatomic.h>
header does not exist in C++. You'll have to provide a way for the C++ code to call C code to get a pointer to the atomic variable you need in a way that hides the type. (Possibly declare a struct that holds the atomic bool, that C++ would only know that the type exists and only know about pointers to it.)
The atomic_bool
type in C and the std::atomic<bool>
type in C++ (typedefed as std::atomic_bool
) are two different types that are unrelated. Passing a std::atomic_bool
to a C function expecting C's atomic_bool
is Undefined Behavior. That it works at all is a combination of luck and the simple definitions of these types being compatible.
If the C++ code needs to call a C function that expects C's atomic_bool
, then that is what it must use. However, the <stdatomic.h>
header does not exist in C++. You'll have to provide a way for the C++ code to call C code to get a pointer to the atomic variable you need in a way that hides the type. (Possibly declare a struct that holds the atomic bool, that C++ would only know that the type exists and only know about pointers to it.)
answered Dec 22 '18 at 20:02
1201ProgramAlarm1201ProgramAlarm
16.5k42439
16.5k42439
It doesn't matter that they are different types. They basically synchronize the same byte of memory via same memory operations.struct A{int x; int y; int z};
andstruct B{int a[3];};
are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior. Same withatomic_bool
andstd::atomic<bool>
.
– ALX23z
Dec 22 '18 at 20:36
1
from developers.redhat.com/blog/2016/01/14/… "The atomic types are fully interoperable between the two languages so that programs can be developed that share objects of atomic types across the language boundary."
– Manny_Mar
Dec 22 '18 at 23:29
1
@ALX23z "are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior" Really?
– Lightness Races in Orbit
Dec 23 '18 at 1:25
@LightnessRacesinOrbit "Really?" Of course, from POV of CPU it is just 3 consecutive integers - 12 bytes of data. Who cares what you called these variables in your source code? Definitely not the program after you compiled it. Perhaps, 100 years into the future they will decide that compiler can rearrange internal variables in any order but it is not the case now or in any foreseeable future. Try and find system whereA a; B *b = (B*)(void*)&a;
won't work correctly.
– ALX23z
Dec 23 '18 at 2:19
3
@ALX23z: "from POV of CPU" doesn't matter. That's not how undefined behavior works.
– user2357112
Dec 23 '18 at 2:22
|
show 1 more comment
It doesn't matter that they are different types. They basically synchronize the same byte of memory via same memory operations.struct A{int x; int y; int z};
andstruct B{int a[3];};
are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior. Same withatomic_bool
andstd::atomic<bool>
.
– ALX23z
Dec 22 '18 at 20:36
1
from developers.redhat.com/blog/2016/01/14/… "The atomic types are fully interoperable between the two languages so that programs can be developed that share objects of atomic types across the language boundary."
– Manny_Mar
Dec 22 '18 at 23:29
1
@ALX23z "are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior" Really?
– Lightness Races in Orbit
Dec 23 '18 at 1:25
@LightnessRacesinOrbit "Really?" Of course, from POV of CPU it is just 3 consecutive integers - 12 bytes of data. Who cares what you called these variables in your source code? Definitely not the program after you compiled it. Perhaps, 100 years into the future they will decide that compiler can rearrange internal variables in any order but it is not the case now or in any foreseeable future. Try and find system whereA a; B *b = (B*)(void*)&a;
won't work correctly.
– ALX23z
Dec 23 '18 at 2:19
3
@ALX23z: "from POV of CPU" doesn't matter. That's not how undefined behavior works.
– user2357112
Dec 23 '18 at 2:22
It doesn't matter that they are different types. They basically synchronize the same byte of memory via same memory operations.
struct A{int x; int y; int z};
and struct B{int a[3];};
are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior. Same with atomic_bool
and std::atomic<bool>
.– ALX23z
Dec 22 '18 at 20:36
It doesn't matter that they are different types. They basically synchronize the same byte of memory via same memory operations.
struct A{int x; int y; int z};
and struct B{int a[3];};
are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior. Same with atomic_bool
and std::atomic<bool>
.– ALX23z
Dec 22 '18 at 20:36
1
1
from developers.redhat.com/blog/2016/01/14/… "The atomic types are fully interoperable between the two languages so that programs can be developed that share objects of atomic types across the language boundary."
– Manny_Mar
Dec 22 '18 at 23:29
from developers.redhat.com/blog/2016/01/14/… "The atomic types are fully interoperable between the two languages so that programs can be developed that share objects of atomic types across the language boundary."
– Manny_Mar
Dec 22 '18 at 23:29
1
1
@ALX23z "are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior" Really?
– Lightness Races in Orbit
Dec 23 '18 at 1:25
@ALX23z "are different but there is no problem when converting one from the other via brute-force conversions. There is no undefined behavior" Really?
– Lightness Races in Orbit
Dec 23 '18 at 1:25
@LightnessRacesinOrbit "Really?" Of course, from POV of CPU it is just 3 consecutive integers - 12 bytes of data. Who cares what you called these variables in your source code? Definitely not the program after you compiled it. Perhaps, 100 years into the future they will decide that compiler can rearrange internal variables in any order but it is not the case now or in any foreseeable future. Try and find system where
A a; B *b = (B*)(void*)&a;
won't work correctly.– ALX23z
Dec 23 '18 at 2:19
@LightnessRacesinOrbit "Really?" Of course, from POV of CPU it is just 3 consecutive integers - 12 bytes of data. Who cares what you called these variables in your source code? Definitely not the program after you compiled it. Perhaps, 100 years into the future they will decide that compiler can rearrange internal variables in any order but it is not the case now or in any foreseeable future. Try and find system where
A a; B *b = (B*)(void*)&a;
won't work correctly.– ALX23z
Dec 23 '18 at 2:19
3
3
@ALX23z: "from POV of CPU" doesn't matter. That's not how undefined behavior works.
– user2357112
Dec 23 '18 at 2:22
@ALX23z: "from POV of CPU" doesn't matter. That's not how undefined behavior works.
– user2357112
Dec 23 '18 at 2:22
|
show 1 more comment
To side-step all ABI issues you may like to implement a C function that is called from C++ and operates on that atomic_bool
. This way your C++ code doesn't need to know anything about that global variable and its type:
In an .h
file:
#ifdef __cplusplus
extern "C" {
#endif
void cancel_my_thread(void);
int is_my_thread_cancelled(void);
#ifdef __cplusplus
}
#endif
And then in a .c
file:
#include <stdatomic.h>
static atomic_bool cancelled = 0;
void cancel_my_thread(void) {
atomic_store_explicit(&cancelled, 1, memory_order_relaxed);
}
int is_my_thread_cancelled(void) {
return atomic_load_explicit(&cancelled, memory_order_relaxed);
}
The C++ code would include that headed and call cancel_my_thread
.
Thank you, it is a sane solution, however in my particular case,do_task
might be called from several threads, so using using global variable wouldn't work. I guess, I'll just wrap it in a struct as @1201ProgramAlarm suggests.
– grepcake
Dec 23 '18 at 9:13
add a comment |
To side-step all ABI issues you may like to implement a C function that is called from C++ and operates on that atomic_bool
. This way your C++ code doesn't need to know anything about that global variable and its type:
In an .h
file:
#ifdef __cplusplus
extern "C" {
#endif
void cancel_my_thread(void);
int is_my_thread_cancelled(void);
#ifdef __cplusplus
}
#endif
And then in a .c
file:
#include <stdatomic.h>
static atomic_bool cancelled = 0;
void cancel_my_thread(void) {
atomic_store_explicit(&cancelled, 1, memory_order_relaxed);
}
int is_my_thread_cancelled(void) {
return atomic_load_explicit(&cancelled, memory_order_relaxed);
}
The C++ code would include that headed and call cancel_my_thread
.
Thank you, it is a sane solution, however in my particular case,do_task
might be called from several threads, so using using global variable wouldn't work. I guess, I'll just wrap it in a struct as @1201ProgramAlarm suggests.
– grepcake
Dec 23 '18 at 9:13
add a comment |
To side-step all ABI issues you may like to implement a C function that is called from C++ and operates on that atomic_bool
. This way your C++ code doesn't need to know anything about that global variable and its type:
In an .h
file:
#ifdef __cplusplus
extern "C" {
#endif
void cancel_my_thread(void);
int is_my_thread_cancelled(void);
#ifdef __cplusplus
}
#endif
And then in a .c
file:
#include <stdatomic.h>
static atomic_bool cancelled = 0;
void cancel_my_thread(void) {
atomic_store_explicit(&cancelled, 1, memory_order_relaxed);
}
int is_my_thread_cancelled(void) {
return atomic_load_explicit(&cancelled, memory_order_relaxed);
}
The C++ code would include that headed and call cancel_my_thread
.
To side-step all ABI issues you may like to implement a C function that is called from C++ and operates on that atomic_bool
. This way your C++ code doesn't need to know anything about that global variable and its type:
In an .h
file:
#ifdef __cplusplus
extern "C" {
#endif
void cancel_my_thread(void);
int is_my_thread_cancelled(void);
#ifdef __cplusplus
}
#endif
And then in a .c
file:
#include <stdatomic.h>
static atomic_bool cancelled = 0;
void cancel_my_thread(void) {
atomic_store_explicit(&cancelled, 1, memory_order_relaxed);
}
int is_my_thread_cancelled(void) {
return atomic_load_explicit(&cancelled, memory_order_relaxed);
}
The C++ code would include that headed and call cancel_my_thread
.
edited Dec 22 '18 at 23:52
answered Dec 22 '18 at 23:37
Maxim EgorushkinMaxim Egorushkin
86.1k11100183
86.1k11100183
Thank you, it is a sane solution, however in my particular case,do_task
might be called from several threads, so using using global variable wouldn't work. I guess, I'll just wrap it in a struct as @1201ProgramAlarm suggests.
– grepcake
Dec 23 '18 at 9:13
add a comment |
Thank you, it is a sane solution, however in my particular case,do_task
might be called from several threads, so using using global variable wouldn't work. I guess, I'll just wrap it in a struct as @1201ProgramAlarm suggests.
– grepcake
Dec 23 '18 at 9:13
Thank you, it is a sane solution, however in my particular case,
do_task
might be called from several threads, so using using global variable wouldn't work. I guess, I'll just wrap it in a struct as @1201ProgramAlarm suggests.– grepcake
Dec 23 '18 at 9:13
Thank you, it is a sane solution, however in my particular case,
do_task
might be called from several threads, so using using global variable wouldn't work. I guess, I'll just wrap it in a struct as @1201ProgramAlarm suggests.– grepcake
Dec 23 '18 at 9:13
add a comment |
I found this on a net search https://developers.redhat.com/blog/2016/01/14/toward-a-better-use-of-c11-atomics-part-1/
Following the lead of C++, along with a memory model describing the
requirements and semantics of multithreaded programs, the C11 standard
adopted a proposal for a set of atomic types and operations into the
language. This change has made it possible to write portable
multi-threaded software that efficiently manipulates objects
indivisibly and without data races. The atomic types are fully
interoperable between the two languages so that programs can be
developed that share objects of atomic types across the language
boundary. This paper examines some of the trade-offs of the design,
points out some of its shortcomings, and outlines solutions that
simplify the use of atomic objects in both languages.
I am just learning about atomics now, but it looks like its compatible between C and CPP.
1
Do you have a more authoritative source than "some guy's blog said it was okay"?
– user2357112
Dec 23 '18 at 2:16
If you read it the paper is about trade-offs of the design, points out some of its shortcomings, and outlines solutions that simplify the use of atomic objects in both languages. He goes into a lot of detail, which I think require some knowledge. I do not claim to be an expert on this. I did read in the past, that C11 got it's atomics from cpp.
– Manny_Mar
Dec 23 '18 at 2:21
add a comment |
I found this on a net search https://developers.redhat.com/blog/2016/01/14/toward-a-better-use-of-c11-atomics-part-1/
Following the lead of C++, along with a memory model describing the
requirements and semantics of multithreaded programs, the C11 standard
adopted a proposal for a set of atomic types and operations into the
language. This change has made it possible to write portable
multi-threaded software that efficiently manipulates objects
indivisibly and without data races. The atomic types are fully
interoperable between the two languages so that programs can be
developed that share objects of atomic types across the language
boundary. This paper examines some of the trade-offs of the design,
points out some of its shortcomings, and outlines solutions that
simplify the use of atomic objects in both languages.
I am just learning about atomics now, but it looks like its compatible between C and CPP.
1
Do you have a more authoritative source than "some guy's blog said it was okay"?
– user2357112
Dec 23 '18 at 2:16
If you read it the paper is about trade-offs of the design, points out some of its shortcomings, and outlines solutions that simplify the use of atomic objects in both languages. He goes into a lot of detail, which I think require some knowledge. I do not claim to be an expert on this. I did read in the past, that C11 got it's atomics from cpp.
– Manny_Mar
Dec 23 '18 at 2:21
add a comment |
I found this on a net search https://developers.redhat.com/blog/2016/01/14/toward-a-better-use-of-c11-atomics-part-1/
Following the lead of C++, along with a memory model describing the
requirements and semantics of multithreaded programs, the C11 standard
adopted a proposal for a set of atomic types and operations into the
language. This change has made it possible to write portable
multi-threaded software that efficiently manipulates objects
indivisibly and without data races. The atomic types are fully
interoperable between the two languages so that programs can be
developed that share objects of atomic types across the language
boundary. This paper examines some of the trade-offs of the design,
points out some of its shortcomings, and outlines solutions that
simplify the use of atomic objects in both languages.
I am just learning about atomics now, but it looks like its compatible between C and CPP.
I found this on a net search https://developers.redhat.com/blog/2016/01/14/toward-a-better-use-of-c11-atomics-part-1/
Following the lead of C++, along with a memory model describing the
requirements and semantics of multithreaded programs, the C11 standard
adopted a proposal for a set of atomic types and operations into the
language. This change has made it possible to write portable
multi-threaded software that efficiently manipulates objects
indivisibly and without data races. The atomic types are fully
interoperable between the two languages so that programs can be
developed that share objects of atomic types across the language
boundary. This paper examines some of the trade-offs of the design,
points out some of its shortcomings, and outlines solutions that
simplify the use of atomic objects in both languages.
I am just learning about atomics now, but it looks like its compatible between C and CPP.
edited Dec 22 '18 at 23:46
answered Dec 22 '18 at 23:32
Manny_MarManny_Mar
1318
1318
1
Do you have a more authoritative source than "some guy's blog said it was okay"?
– user2357112
Dec 23 '18 at 2:16
If you read it the paper is about trade-offs of the design, points out some of its shortcomings, and outlines solutions that simplify the use of atomic objects in both languages. He goes into a lot of detail, which I think require some knowledge. I do not claim to be an expert on this. I did read in the past, that C11 got it's atomics from cpp.
– Manny_Mar
Dec 23 '18 at 2:21
add a comment |
1
Do you have a more authoritative source than "some guy's blog said it was okay"?
– user2357112
Dec 23 '18 at 2:16
If you read it the paper is about trade-offs of the design, points out some of its shortcomings, and outlines solutions that simplify the use of atomic objects in both languages. He goes into a lot of detail, which I think require some knowledge. I do not claim to be an expert on this. I did read in the past, that C11 got it's atomics from cpp.
– Manny_Mar
Dec 23 '18 at 2:21
1
1
Do you have a more authoritative source than "some guy's blog said it was okay"?
– user2357112
Dec 23 '18 at 2:16
Do you have a more authoritative source than "some guy's blog said it was okay"?
– user2357112
Dec 23 '18 at 2:16
If you read it the paper is about trade-offs of the design, points out some of its shortcomings, and outlines solutions that simplify the use of atomic objects in both languages. He goes into a lot of detail, which I think require some knowledge. I do not claim to be an expert on this. I did read in the past, that C11 got it's atomics from cpp.
– Manny_Mar
Dec 23 '18 at 2:21
If you read it the paper is about trade-offs of the design, points out some of its shortcomings, and outlines solutions that simplify the use of atomic objects in both languages. He goes into a lot of detail, which I think require some knowledge. I do not claim to be an expert on this. I did read in the past, that C11 got it's atomics from cpp.
– Manny_Mar
Dec 23 '18 at 2:21
add a comment |
how i understand your code in general is (must be) next
// c code
void _do_task();
void do_task(volatile bool *cancelled)
{
do {
_do_task();
} while (!*cancelled);
}
// c++ code
volatile bool g_cancelled;// can be modify by another thread
do_task(&cancelled);
void some_proc()
{
//...
g_cancelled = true;
}
i be ask question - are here we need declare cancelled
as atomic ? are we need atomic here ?
atomic need in 3 case:
we do Read-Modify-Write operation. say if we need set
cancelled
to true and check are it was alreadytrue
. this for example can be need if several threads setcancelled
to true and who do this first need free some resources.
if (!cancelled.exchange(true)) { free_resources(); }
the read or write operation for type need to be atomic. of course on
all current and all possible future implementations this is true for
bool type (despite formal not defined). but even this is not
important. we here checkcancelled
only for 2 values - 0 (false
) and
all another. so even if both write and read operation on
cancelled assume not atomic, after one thread write non-zero to
canceled, another thread sooner or later will read modified non-zero value
fromcanceled
. even if it will be another value, not the same
first thread write: for example ifcancelled = true
translated to
mov cancelled, -1; mov cancelled, 1
- two hardware, not atomic
operation - second thread can read-1
instead final1
(true
)
from canceled, but this not play role if we check only for non-zero - all
another values break loop -while (!*cancelled);
if we use here atomic operation for write/readcancelled
- nothing change here - after one thread atomic write to it another thread sooner or later will read modified non-zero value from canceled - atomic operation or not - memory is common - if one thread write to memory (atomic or no) another threads sooner or later will view this memory modification.- we need synchronize another read/writes with cancelled. so we need
synchronization point between 2 threads aroundcanceled
with memory
order other thanmemory_order_relaxed
say for example next code:
//
void _do_task();
int result;
void do_task(atomic_bool *cancelled)
{
do {
_do_task();
} while (!g_cancelled.load(memory_order_acquire));
switch(result)
{
case 1:
//...
break;
}
}
void some_proc()
{
result = 1;
g_cancelled.store(true, memory_order_release);
}
so we not simply set g_cancelled
to true here, but before this
write some shared data (result
) and want that another thread after
view modification of g_cancelled, will be also view modification of
shared data (result
). but i doubt that you actually use/need this
scenario
if none of this 3 things is need- you not need atomic here. what you really need - that one thread just write true to cancelled
and another thread all time read value of cancelled
(instead do this once and cache result). usual in most case of code this will be done auto, but for be exactly you need declare canceled as volatile
if however you by some reason need exactly atomic (atomic_bool
), because you here cross the border of languages, you need understand concrete implementation of atomic_bool
in both languages and are it the same (type declaration, operations (load, store, etc)). by fact atomic_bool
is the same for c and c++.
or (better) instead of make visible and share type atomic_bool
use interface functions like
bool is_canceled(void* cancelled);
so code can be next
// c code
void _do_task();
bool is_canceled(void* cancelled);
void do_task(void *cancelled)
{
do {
_do_task();
} while (!is_canceled(cancelled));
}
// c++ code
atomic_bool g_cancelled;// can be modify by another thread
bool is_canceled(void* cancelled)
{
return *reinterpret_cast<atomic_bool*>(cancelled);
}
void some_proc()
{
//...
g_cancelled = true;
}
do_task(&g_cancelled);
but again i doubt that in your task you need atomic_bool
by semantic. you need volatile bool
add a comment |
how i understand your code in general is (must be) next
// c code
void _do_task();
void do_task(volatile bool *cancelled)
{
do {
_do_task();
} while (!*cancelled);
}
// c++ code
volatile bool g_cancelled;// can be modify by another thread
do_task(&cancelled);
void some_proc()
{
//...
g_cancelled = true;
}
i be ask question - are here we need declare cancelled
as atomic ? are we need atomic here ?
atomic need in 3 case:
we do Read-Modify-Write operation. say if we need set
cancelled
to true and check are it was alreadytrue
. this for example can be need if several threads setcancelled
to true and who do this first need free some resources.
if (!cancelled.exchange(true)) { free_resources(); }
the read or write operation for type need to be atomic. of course on
all current and all possible future implementations this is true for
bool type (despite formal not defined). but even this is not
important. we here checkcancelled
only for 2 values - 0 (false
) and
all another. so even if both write and read operation on
cancelled assume not atomic, after one thread write non-zero to
canceled, another thread sooner or later will read modified non-zero value
fromcanceled
. even if it will be another value, not the same
first thread write: for example ifcancelled = true
translated to
mov cancelled, -1; mov cancelled, 1
- two hardware, not atomic
operation - second thread can read-1
instead final1
(true
)
from canceled, but this not play role if we check only for non-zero - all
another values break loop -while (!*cancelled);
if we use here atomic operation for write/readcancelled
- nothing change here - after one thread atomic write to it another thread sooner or later will read modified non-zero value from canceled - atomic operation or not - memory is common - if one thread write to memory (atomic or no) another threads sooner or later will view this memory modification.- we need synchronize another read/writes with cancelled. so we need
synchronization point between 2 threads aroundcanceled
with memory
order other thanmemory_order_relaxed
say for example next code:
//
void _do_task();
int result;
void do_task(atomic_bool *cancelled)
{
do {
_do_task();
} while (!g_cancelled.load(memory_order_acquire));
switch(result)
{
case 1:
//...
break;
}
}
void some_proc()
{
result = 1;
g_cancelled.store(true, memory_order_release);
}
so we not simply set g_cancelled
to true here, but before this
write some shared data (result
) and want that another thread after
view modification of g_cancelled, will be also view modification of
shared data (result
). but i doubt that you actually use/need this
scenario
if none of this 3 things is need- you not need atomic here. what you really need - that one thread just write true to cancelled
and another thread all time read value of cancelled
(instead do this once and cache result). usual in most case of code this will be done auto, but for be exactly you need declare canceled as volatile
if however you by some reason need exactly atomic (atomic_bool
), because you here cross the border of languages, you need understand concrete implementation of atomic_bool
in both languages and are it the same (type declaration, operations (load, store, etc)). by fact atomic_bool
is the same for c and c++.
or (better) instead of make visible and share type atomic_bool
use interface functions like
bool is_canceled(void* cancelled);
so code can be next
// c code
void _do_task();
bool is_canceled(void* cancelled);
void do_task(void *cancelled)
{
do {
_do_task();
} while (!is_canceled(cancelled));
}
// c++ code
atomic_bool g_cancelled;// can be modify by another thread
bool is_canceled(void* cancelled)
{
return *reinterpret_cast<atomic_bool*>(cancelled);
}
void some_proc()
{
//...
g_cancelled = true;
}
do_task(&g_cancelled);
but again i doubt that in your task you need atomic_bool
by semantic. you need volatile bool
add a comment |
how i understand your code in general is (must be) next
// c code
void _do_task();
void do_task(volatile bool *cancelled)
{
do {
_do_task();
} while (!*cancelled);
}
// c++ code
volatile bool g_cancelled;// can be modify by another thread
do_task(&cancelled);
void some_proc()
{
//...
g_cancelled = true;
}
i be ask question - are here we need declare cancelled
as atomic ? are we need atomic here ?
atomic need in 3 case:
we do Read-Modify-Write operation. say if we need set
cancelled
to true and check are it was alreadytrue
. this for example can be need if several threads setcancelled
to true and who do this first need free some resources.
if (!cancelled.exchange(true)) { free_resources(); }
the read or write operation for type need to be atomic. of course on
all current and all possible future implementations this is true for
bool type (despite formal not defined). but even this is not
important. we here checkcancelled
only for 2 values - 0 (false
) and
all another. so even if both write and read operation on
cancelled assume not atomic, after one thread write non-zero to
canceled, another thread sooner or later will read modified non-zero value
fromcanceled
. even if it will be another value, not the same
first thread write: for example ifcancelled = true
translated to
mov cancelled, -1; mov cancelled, 1
- two hardware, not atomic
operation - second thread can read-1
instead final1
(true
)
from canceled, but this not play role if we check only for non-zero - all
another values break loop -while (!*cancelled);
if we use here atomic operation for write/readcancelled
- nothing change here - after one thread atomic write to it another thread sooner or later will read modified non-zero value from canceled - atomic operation or not - memory is common - if one thread write to memory (atomic or no) another threads sooner or later will view this memory modification.- we need synchronize another read/writes with cancelled. so we need
synchronization point between 2 threads aroundcanceled
with memory
order other thanmemory_order_relaxed
say for example next code:
//
void _do_task();
int result;
void do_task(atomic_bool *cancelled)
{
do {
_do_task();
} while (!g_cancelled.load(memory_order_acquire));
switch(result)
{
case 1:
//...
break;
}
}
void some_proc()
{
result = 1;
g_cancelled.store(true, memory_order_release);
}
so we not simply set g_cancelled
to true here, but before this
write some shared data (result
) and want that another thread after
view modification of g_cancelled, will be also view modification of
shared data (result
). but i doubt that you actually use/need this
scenario
if none of this 3 things is need- you not need atomic here. what you really need - that one thread just write true to cancelled
and another thread all time read value of cancelled
(instead do this once and cache result). usual in most case of code this will be done auto, but for be exactly you need declare canceled as volatile
if however you by some reason need exactly atomic (atomic_bool
), because you here cross the border of languages, you need understand concrete implementation of atomic_bool
in both languages and are it the same (type declaration, operations (load, store, etc)). by fact atomic_bool
is the same for c and c++.
or (better) instead of make visible and share type atomic_bool
use interface functions like
bool is_canceled(void* cancelled);
so code can be next
// c code
void _do_task();
bool is_canceled(void* cancelled);
void do_task(void *cancelled)
{
do {
_do_task();
} while (!is_canceled(cancelled));
}
// c++ code
atomic_bool g_cancelled;// can be modify by another thread
bool is_canceled(void* cancelled)
{
return *reinterpret_cast<atomic_bool*>(cancelled);
}
void some_proc()
{
//...
g_cancelled = true;
}
do_task(&g_cancelled);
but again i doubt that in your task you need atomic_bool
by semantic. you need volatile bool
how i understand your code in general is (must be) next
// c code
void _do_task();
void do_task(volatile bool *cancelled)
{
do {
_do_task();
} while (!*cancelled);
}
// c++ code
volatile bool g_cancelled;// can be modify by another thread
do_task(&cancelled);
void some_proc()
{
//...
g_cancelled = true;
}
i be ask question - are here we need declare cancelled
as atomic ? are we need atomic here ?
atomic need in 3 case:
we do Read-Modify-Write operation. say if we need set
cancelled
to true and check are it was alreadytrue
. this for example can be need if several threads setcancelled
to true and who do this first need free some resources.
if (!cancelled.exchange(true)) { free_resources(); }
the read or write operation for type need to be atomic. of course on
all current and all possible future implementations this is true for
bool type (despite formal not defined). but even this is not
important. we here checkcancelled
only for 2 values - 0 (false
) and
all another. so even if both write and read operation on
cancelled assume not atomic, after one thread write non-zero to
canceled, another thread sooner or later will read modified non-zero value
fromcanceled
. even if it will be another value, not the same
first thread write: for example ifcancelled = true
translated to
mov cancelled, -1; mov cancelled, 1
- two hardware, not atomic
operation - second thread can read-1
instead final1
(true
)
from canceled, but this not play role if we check only for non-zero - all
another values break loop -while (!*cancelled);
if we use here atomic operation for write/readcancelled
- nothing change here - after one thread atomic write to it another thread sooner or later will read modified non-zero value from canceled - atomic operation or not - memory is common - if one thread write to memory (atomic or no) another threads sooner or later will view this memory modification.- we need synchronize another read/writes with cancelled. so we need
synchronization point between 2 threads aroundcanceled
with memory
order other thanmemory_order_relaxed
say for example next code:
//
void _do_task();
int result;
void do_task(atomic_bool *cancelled)
{
do {
_do_task();
} while (!g_cancelled.load(memory_order_acquire));
switch(result)
{
case 1:
//...
break;
}
}
void some_proc()
{
result = 1;
g_cancelled.store(true, memory_order_release);
}
so we not simply set g_cancelled
to true here, but before this
write some shared data (result
) and want that another thread after
view modification of g_cancelled, will be also view modification of
shared data (result
). but i doubt that you actually use/need this
scenario
if none of this 3 things is need- you not need atomic here. what you really need - that one thread just write true to cancelled
and another thread all time read value of cancelled
(instead do this once and cache result). usual in most case of code this will be done auto, but for be exactly you need declare canceled as volatile
if however you by some reason need exactly atomic (atomic_bool
), because you here cross the border of languages, you need understand concrete implementation of atomic_bool
in both languages and are it the same (type declaration, operations (load, store, etc)). by fact atomic_bool
is the same for c and c++.
or (better) instead of make visible and share type atomic_bool
use interface functions like
bool is_canceled(void* cancelled);
so code can be next
// c code
void _do_task();
bool is_canceled(void* cancelled);
void do_task(void *cancelled)
{
do {
_do_task();
} while (!is_canceled(cancelled));
}
// c++ code
atomic_bool g_cancelled;// can be modify by another thread
bool is_canceled(void* cancelled)
{
return *reinterpret_cast<atomic_bool*>(cancelled);
}
void some_proc()
{
//...
g_cancelled = true;
}
do_task(&g_cancelled);
but again i doubt that in your task you need atomic_bool
by semantic. you need volatile bool
edited Dec 23 '18 at 9:07
answered Dec 23 '18 at 0:18
RbMmRbMm
17.4k11224
17.4k11224
add a comment |
add a comment |
Atomicity of operations is caused by hardware, not software (well, in C++ there are also "atomic" variables that are atomic in name only, those are implemented via mutexes and locks). So, basically, C++ atomics and C atomics do the very same thing. Hence as long as the types are compatible there won't be issues. And C++11 and C11 atomic classes were made to be compatible.
Apparently, people do not understand how atomics and locks work and require further explanation. Check out current memory models for more information.
1) We will start with basics. What and why are atomics? How does memory works?
Memory Model: think of processor as several independent cores and each has its own memory (cashes L1, L2, and L3; and in fact, L3 cash is common but it isn't really important).
Why do we need atomic operation?
If you don't use atomics, then each processor might have its own version of the variable 'x' and they are in general not synchronized. There is no telling when they will perform synchronizations with RAM/L3 cash.
When atomic operations are used, such memory operations are used that ensure synchronization with RAM/L3 cash (or whatever is needed) - ensuring that different cores have access to the same variable and not have variety of different versions of it.
Nobody cares if it is C, C++, or whatever language you use - as long as one ensures memory synchronization (both read, write, and modify) there will never be no issues.
2) OK, what about locks and mutexes?
Mutexes tend to work with OS and have queue over which thread should be allowed next to perform. And they enforce stricter memory synchronization than atomics do. With atomics one can syhchronize just the variable itself or more depending on the request / which function you call.
3) Say I have atomic_bool, can it work in interchangeably on different languages (C/C++11)?
Normally a boolean can be sychronized via memory operations (you're just synchronizing a single byte of memory from their perspective).
If the compilers are aware that the hardware can perform such operations then they surely will use them as long as you use the standard.
Logical atomics (any std::atomic< T > with T having wrong size/alignment) are synchronized via locks. In this case it is unlikely that different languages can use them interchangeably - if they have different methods of usage of these locks, or for some reason one decided to use a lock and the other one came to conclusion that it can work with atomic hardware memory synchronizations... then there will be issues.
If you use atomic_bool on any modern machine with C/C++, it will surely be able to synchronize without locks.
8
"And C++11 and C11 atomic classes were made to be compatible" Can you cite any source for this claim? Moreover, std::atomic_bool is not guaranteed to be lock free as opposed to std::atomic_flag.
– idmean
Dec 22 '18 at 19:12
@idmean atomic_bool is not guaranteed to be lock free by the standart, as it doesn't require it to be. Whether it is lock free or not is something you ought to ask hardware whether it supports atomic operations. Locks are also in sense atomics, as they force more strict memory syncronization, while atomics allow way more relaxed memory sync.
– ALX23z
Dec 22 '18 at 19:22
It reads like a rant by a newcomer who's mad that experts are telling them they're wrong.
– R..
Dec 23 '18 at 8:18
add a comment |
Atomicity of operations is caused by hardware, not software (well, in C++ there are also "atomic" variables that are atomic in name only, those are implemented via mutexes and locks). So, basically, C++ atomics and C atomics do the very same thing. Hence as long as the types are compatible there won't be issues. And C++11 and C11 atomic classes were made to be compatible.
Apparently, people do not understand how atomics and locks work and require further explanation. Check out current memory models for more information.
1) We will start with basics. What and why are atomics? How does memory works?
Memory Model: think of processor as several independent cores and each has its own memory (cashes L1, L2, and L3; and in fact, L3 cash is common but it isn't really important).
Why do we need atomic operation?
If you don't use atomics, then each processor might have its own version of the variable 'x' and they are in general not synchronized. There is no telling when they will perform synchronizations with RAM/L3 cash.
When atomic operations are used, such memory operations are used that ensure synchronization with RAM/L3 cash (or whatever is needed) - ensuring that different cores have access to the same variable and not have variety of different versions of it.
Nobody cares if it is C, C++, or whatever language you use - as long as one ensures memory synchronization (both read, write, and modify) there will never be no issues.
2) OK, what about locks and mutexes?
Mutexes tend to work with OS and have queue over which thread should be allowed next to perform. And they enforce stricter memory synchronization than atomics do. With atomics one can syhchronize just the variable itself or more depending on the request / which function you call.
3) Say I have atomic_bool, can it work in interchangeably on different languages (C/C++11)?
Normally a boolean can be sychronized via memory operations (you're just synchronizing a single byte of memory from their perspective).
If the compilers are aware that the hardware can perform such operations then they surely will use them as long as you use the standard.
Logical atomics (any std::atomic< T > with T having wrong size/alignment) are synchronized via locks. In this case it is unlikely that different languages can use them interchangeably - if they have different methods of usage of these locks, or for some reason one decided to use a lock and the other one came to conclusion that it can work with atomic hardware memory synchronizations... then there will be issues.
If you use atomic_bool on any modern machine with C/C++, it will surely be able to synchronize without locks.
8
"And C++11 and C11 atomic classes were made to be compatible" Can you cite any source for this claim? Moreover, std::atomic_bool is not guaranteed to be lock free as opposed to std::atomic_flag.
– idmean
Dec 22 '18 at 19:12
@idmean atomic_bool is not guaranteed to be lock free by the standart, as it doesn't require it to be. Whether it is lock free or not is something you ought to ask hardware whether it supports atomic operations. Locks are also in sense atomics, as they force more strict memory syncronization, while atomics allow way more relaxed memory sync.
– ALX23z
Dec 22 '18 at 19:22
It reads like a rant by a newcomer who's mad that experts are telling them they're wrong.
– R..
Dec 23 '18 at 8:18
add a comment |
Atomicity of operations is caused by hardware, not software (well, in C++ there are also "atomic" variables that are atomic in name only, those are implemented via mutexes and locks). So, basically, C++ atomics and C atomics do the very same thing. Hence as long as the types are compatible there won't be issues. And C++11 and C11 atomic classes were made to be compatible.
Apparently, people do not understand how atomics and locks work and require further explanation. Check out current memory models for more information.
1) We will start with basics. What and why are atomics? How does memory works?
Memory Model: think of processor as several independent cores and each has its own memory (cashes L1, L2, and L3; and in fact, L3 cash is common but it isn't really important).
Why do we need atomic operation?
If you don't use atomics, then each processor might have its own version of the variable 'x' and they are in general not synchronized. There is no telling when they will perform synchronizations with RAM/L3 cash.
When atomic operations are used, such memory operations are used that ensure synchronization with RAM/L3 cash (or whatever is needed) - ensuring that different cores have access to the same variable and not have variety of different versions of it.
Nobody cares if it is C, C++, or whatever language you use - as long as one ensures memory synchronization (both read, write, and modify) there will never be no issues.
2) OK, what about locks and mutexes?
Mutexes tend to work with OS and have queue over which thread should be allowed next to perform. And they enforce stricter memory synchronization than atomics do. With atomics one can syhchronize just the variable itself or more depending on the request / which function you call.
3) Say I have atomic_bool, can it work in interchangeably on different languages (C/C++11)?
Normally a boolean can be sychronized via memory operations (you're just synchronizing a single byte of memory from their perspective).
If the compilers are aware that the hardware can perform such operations then they surely will use them as long as you use the standard.
Logical atomics (any std::atomic< T > with T having wrong size/alignment) are synchronized via locks. In this case it is unlikely that different languages can use them interchangeably - if they have different methods of usage of these locks, or for some reason one decided to use a lock and the other one came to conclusion that it can work with atomic hardware memory synchronizations... then there will be issues.
If you use atomic_bool on any modern machine with C/C++, it will surely be able to synchronize without locks.
Atomicity of operations is caused by hardware, not software (well, in C++ there are also "atomic" variables that are atomic in name only, those are implemented via mutexes and locks). So, basically, C++ atomics and C atomics do the very same thing. Hence as long as the types are compatible there won't be issues. And C++11 and C11 atomic classes were made to be compatible.
Apparently, people do not understand how atomics and locks work and require further explanation. Check out current memory models for more information.
1) We will start with basics. What and why are atomics? How does memory works?
Memory Model: think of processor as several independent cores and each has its own memory (cashes L1, L2, and L3; and in fact, L3 cash is common but it isn't really important).
Why do we need atomic operation?
If you don't use atomics, then each processor might have its own version of the variable 'x' and they are in general not synchronized. There is no telling when they will perform synchronizations with RAM/L3 cash.
When atomic operations are used, such memory operations are used that ensure synchronization with RAM/L3 cash (or whatever is needed) - ensuring that different cores have access to the same variable and not have variety of different versions of it.
Nobody cares if it is C, C++, or whatever language you use - as long as one ensures memory synchronization (both read, write, and modify) there will never be no issues.
2) OK, what about locks and mutexes?
Mutexes tend to work with OS and have queue over which thread should be allowed next to perform. And they enforce stricter memory synchronization than atomics do. With atomics one can syhchronize just the variable itself or more depending on the request / which function you call.
3) Say I have atomic_bool, can it work in interchangeably on different languages (C/C++11)?
Normally a boolean can be sychronized via memory operations (you're just synchronizing a single byte of memory from their perspective).
If the compilers are aware that the hardware can perform such operations then they surely will use them as long as you use the standard.
Logical atomics (any std::atomic< T > with T having wrong size/alignment) are synchronized via locks. In this case it is unlikely that different languages can use them interchangeably - if they have different methods of usage of these locks, or for some reason one decided to use a lock and the other one came to conclusion that it can work with atomic hardware memory synchronizations... then there will be issues.
If you use atomic_bool on any modern machine with C/C++, it will surely be able to synchronize without locks.
edited Dec 22 '18 at 21:44
answered Dec 22 '18 at 19:05
ALX23zALX23z
1275
1275
8
"And C++11 and C11 atomic classes were made to be compatible" Can you cite any source for this claim? Moreover, std::atomic_bool is not guaranteed to be lock free as opposed to std::atomic_flag.
– idmean
Dec 22 '18 at 19:12
@idmean atomic_bool is not guaranteed to be lock free by the standart, as it doesn't require it to be. Whether it is lock free or not is something you ought to ask hardware whether it supports atomic operations. Locks are also in sense atomics, as they force more strict memory syncronization, while atomics allow way more relaxed memory sync.
– ALX23z
Dec 22 '18 at 19:22
It reads like a rant by a newcomer who's mad that experts are telling them they're wrong.
– R..
Dec 23 '18 at 8:18
add a comment |
8
"And C++11 and C11 atomic classes were made to be compatible" Can you cite any source for this claim? Moreover, std::atomic_bool is not guaranteed to be lock free as opposed to std::atomic_flag.
– idmean
Dec 22 '18 at 19:12
@idmean atomic_bool is not guaranteed to be lock free by the standart, as it doesn't require it to be. Whether it is lock free or not is something you ought to ask hardware whether it supports atomic operations. Locks are also in sense atomics, as they force more strict memory syncronization, while atomics allow way more relaxed memory sync.
– ALX23z
Dec 22 '18 at 19:22
It reads like a rant by a newcomer who's mad that experts are telling them they're wrong.
– R..
Dec 23 '18 at 8:18
8
8
"And C++11 and C11 atomic classes were made to be compatible" Can you cite any source for this claim? Moreover, std::atomic_bool is not guaranteed to be lock free as opposed to std::atomic_flag.
– idmean
Dec 22 '18 at 19:12
"And C++11 and C11 atomic classes were made to be compatible" Can you cite any source for this claim? Moreover, std::atomic_bool is not guaranteed to be lock free as opposed to std::atomic_flag.
– idmean
Dec 22 '18 at 19:12
@idmean atomic_bool is not guaranteed to be lock free by the standart, as it doesn't require it to be. Whether it is lock free or not is something you ought to ask hardware whether it supports atomic operations. Locks are also in sense atomics, as they force more strict memory syncronization, while atomics allow way more relaxed memory sync.
– ALX23z
Dec 22 '18 at 19:22
@idmean atomic_bool is not guaranteed to be lock free by the standart, as it doesn't require it to be. Whether it is lock free or not is something you ought to ask hardware whether it supports atomic operations. Locks are also in sense atomics, as they force more strict memory syncronization, while atomics allow way more relaxed memory sync.
– ALX23z
Dec 22 '18 at 19:22
It reads like a rant by a newcomer who's mad that experts are telling them they're wrong.
– R..
Dec 23 '18 at 8:18
It reads like a rant by a newcomer who's mad that experts are telling them they're wrong.
– R..
Dec 23 '18 at 8:18
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%2f53898429%2finteroperabilty-between-c-and-c-atomics%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
for what you here need atomic ? which operation need to be atomic ? nothing. you here need volatile by sense, but not atomic -
void do_task(volatile bool *cancelled);
– RbMm
Dec 22 '18 at 21:47
really in most case you even not need volatile if inside loop
do { * } while (!*cancelled);
you call some external function, for which compiler can not know - are it modify*cancelled
– RbMm
Dec 22 '18 at 21:56
@RbMm: Advice to do things that might happen to work on current tooling but that is explicitly wrong and has no advantages over doing it right is not helpful.
– R..
Dec 23 '18 at 8:14
@R.. - why this is explicitly wrong ? of course without view complete code can not exactly say are need atomic here, but how usual cancelled use - not require any atomic or memory order other than relaxed. need only volatile.
– RbMm
Dec 23 '18 at 8:37
@RbMn one threads reads a variable. one thread writes it. all without further synchronization-> you need atomic. end of story.
– phön
Dec 23 '18 at 9:32