Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interoperabilty between C and C++ atomics

Tags:

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.

like image 766
grepcake Avatar asked Dec 22 '18 18:12

grepcake


3 Answers

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.)

like image 115
1201ProgramAlarm Avatar answered Oct 07 '22 09:10

1201ProgramAlarm


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 .hfile:

#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.

like image 22
Maxim Egorushkin Avatar answered Oct 07 '22 08:10

Maxim Egorushkin


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.

EDIT

Another source Multi-Threading support in c11

like image 1
Manny_Mar Avatar answered Oct 07 '22 07:10

Manny_Mar