Reputation: 1
I am trying to implement a global version clock that is accessed by multiple threads, so it should be atomic as far as I know to ensure thread safety. To modify and read the values I implemented the methods below, however I get the warning "Incompatible pointer types passing 'typeof ((void) 0 , *__atomic_load_ptr) *' (aka 'unsigned long *') to parameter of type '_Atomic(unsigned long) *'" on the atomic_load_explicit and atomic_compare_exchange_strong_explicit function calls.
More specifically, the warning says:
Incompatible pointer types passing 'typeof ((void) 0 , *__atomic_exchange_ptr) *' (aka 'int *') to parameter of type '_Atomic(int) *'
Declared in: stdatomic. h
Definition:
#define atomic_init(PTR, VAL) \
atomic_store_explicit (PTR, VAL, __ATOMIC_RELAXED)
Replacement:
({
__auto_type __atomic_store_ptr = (&(lock->lock_state));
__typeof__((void) 0, *__atomic_store_ptr) __atomic_store_tmp = (0);
__atomic_store(__atomic_store_ptr, &__atomic_store_tmp, (0));
})
I can clear the warning by not using _Atomic, but I am not convinced it would be thread safe, what would be the solution?
Written in C11, gcc version 13.2.0, Ubuntu 24.04 LTS
Thanks!
#include <stdatomic.h>
_Atomic unsigned long global_version_clock = 0;
uint64_t get_current_version() {
return atomic_load_explicit(&global_version_clock, memory_order_acquire);
}
uint64_t increment_version() {
uint64_t old_version, new_version;
do {
old_version = atomic_load_explicit(&global_version_clock, memory_order_relaxed);
new_version = old_version + 1;
} while (!atomic_compare_exchange_strong_explicit(&global_version_clock, &old_version, new_version,
memory_order_release, memory_order_relaxed));
return new_version;
}
Edit:
I am now using this struct in the header file:
#include <stdatomic.h>
#include <stdint-gcc.h>
#include <stdbool.h>
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifndef __USE_XOPEN2K
#define __USE_XOPEN2K
#endif
typedef struct version_clock_t{
_Atomic uint64_t version;
}version_clock_t;
bool init_version_clock(version_clock_t* global_version_clock);
uint64_t get_current_version(version_clock_t* global_version_clock);
uint64_t increment_version(version_clock_t* global_version_clock);
And in the C file I implement the declared functions, which still gives the warnings "Incompatible pointer types passing 'typeof ((void) 0 , *__atomic_store_ptr) *' (aka 'unsigned long *') to parameter of type '_Atomic(uint64_t) *'" and "Incompatible pointer types passing 'typeof ((void) 0 , *__atomic_load_ptr) *' (aka 'unsigned long *') to parameter of type '_Atomic(uint64_t) *'" respectively:
#include "version-clock.h"
bool init_version_clock(version_clock_t* global_version_clock) {
atomic_init(&(global_version_clock->version), 0); // Warning here
return true;
}
uint64_t get_current_version(version_clock_t* global_version_clock) {
return atomic_load(&(global_version_clock->version)); // Warning here
}
uint64_t increment_version(version_clock_t* global_version_clock) {
return atomic_fetch_add(&(global_version_clock->version), 1) + 1;
}
Upvotes: 0
Views: 85
Reputation: 67835
The type of global_version_clock
is declared as _Atomic unsigned long
, while the function increment_version()
uses uint64_t
for old_version
and new_version
. The atomic_compare_exchange_strong_explicit
function will issue a type compatibility warning if the types are not the same.
Solution use the same types uint64_t
or unsigned long
.
_Atomic uint64_t global_version_clock = 0;
uint64_t get_current_version() {
return atomic_load_explicit(&global_version_clock, memory_order_acquire);
}
uint64_t increment_version() {
uint64_t old_version, new_version;
do {
old_version = atomic_load_explicit(&global_version_clock, memory_order_relaxed);
new_version = old_version + 1;
} while (!atomic_compare_exchange_strong_explicit(&global_version_clock, &old_version, new_version,
memory_order_release, memory_order_relaxed));
return new_version;
}
Remember that unsigned long
does not have to be 64 bits long!
Upvotes: 1