0

Here is an example:

This is safe:

std::atomic_int i;

// Thread 1
i = 4;

// Thread 2
std::cout << i.load();

But is this safe to write:

std::atomic_int *i = new std::atomic_int;

// Thread 1
*i = 4;

// Thread 2
std::count << (*i).load();

My main rationale is that I want to have vector of atomics. Since atomics are not CopyConstructible, I need pointers to atomics to store into vector.

toxic
  • 39
  • 5
  • No it's not safe, because the pointer itself is not atomic. Only the object that the variable is pointing to. – Some programmer dude Jun 09 '23 at 07:21
  • But if one never changes the value of the actual pointer (you can actually declare it as const pointer), are the underlying stores/loads still atomic? I think they definitely are. Otherwise there is no way to have vector of atomics unless you use pointers to atomics. – toxic Jun 09 '23 at 07:23
  • 2
    If you can 100% guarantee that the pointer variable itself won't be modified, then yes the loads and stores are just the same. You're still using the atomic object the same. – Some programmer dude Jun 09 '23 at 07:26
  • 2
    If there's a happens-before relationship between the completion of the assignment to the pointer and to reading the pointer on the threads, there's no problem. If there isn't, you've got a problem. In addition you also need a happens-before relationship between the last operation on the dereferenced pointer object on the threads and the destruction of the object... – fabian Jun 09 '23 at 07:26
  • 2
    On a different note, instead of `(*i).load()`, why not `i->load()`? – Some programmer dude Jun 09 '23 at 07:26
  • Note that the code shown can still result in undefined behaviour, since the atomic is not guaranteed to be initialized with a value before `i.load()` on thread 2. – fabian Jun 09 '23 at 07:32
  • Does this answer your question? [How to declare a vector of atomic in C++](https://stackoverflow.com/questions/13193484/how-to-declare-a-vector-of-atomic-in-c) – Öö Tiib Jun 09 '23 at 07:36
  • Thank you @fabian, I understand that and will be careful about it. Unfortunately this question does not help me that much, because I don't want a custom ad-hoc wrapper class. I just want to use standard atomic class from standard library – toxic Jun 09 '23 at 07:58
  • Do you have a C++-20 implementation? If so, you can use a vector of integers and work with them via `std::atomic_ref`. If not, you can go with another container that does not require a copy/move constructor when adding elements (such as `std::deque`). Live demo: https://godbolt.org/z/8nrh41T6c. – Daniel Langr Jun 09 '23 at 08:04

1 Answers1

3

Yes, it's safe, assuming that new std::atomic_int happens before both threads are started (or the access to the pointer itself is synchronized in some other way).

Note that before C++20 atomics are not zeroed by default, so if .load() happened before the write, it would cause UB.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207