Whilst trying to work with std atomic pointer, I ran into the following. Say I do this:
std::atomic<std::string*> myString;
// <do fancy stuff with the string... also on other threads>
//A can I do this?
myString.load()->size()
//B can I do this?
char myFifthChar = *(myString.load()->c_str() + 5);
//C can I do this?
char myCharArray[255];
strcpy(myCharArray, myString.load()->c_str());
I'm pretty sure C is illegal because myString might be deleted in the meantime.
However I'm unsure about A and B. I suppose they are illegal since the pointer might be deferenced whilst performing the read operation.
However if this is the case, how can you ever read from an atomic pointer that might be deleted. Since the load is 1 step, and the reading of the data is 1 step.
Dereferencing is used to access or manipulate data contained in memory location pointed to by a pointer. *(asterisk) is used with pointer variable when dereferencing the pointer variable, it refers to variable being pointed, so this is called dereferencing of pointers.
In computer programming, a dereference operator, also known as an indirection operator, operates on a pointer variable. It returns the location value, or l-value in memory pointed to by the variable's value. In the C programming language, the deference operator is denoted with an asterisk (*).
// A can I do this?
myString.load()->size()
Yes you can, but you do have a race condition if something else might be mutating or destructing/deallocating the string
to which the snapshot of myString
you received points. In other words, the situation after atomically retrieving the pointer is the same as for any std::string
object to which multiple threads might have pointers, except that...
There is the question of whether the atomic load
guarantees some particular construction/change to the string
- perhaps performed by whichever thread updated myString
to point to the particular string
instance you've load
ed a pointer to - will be visible to you. The default is to ensure this, but you might want to read over this explanation of the memory_order
parameter to load()
. Note that not explicitly asking for memory synchronisation does not keep you safe from mutating/destruction by other threads.
So, say myString()
is pointed successively at string
's a
, b
then c
, and your code retrieves &b
... as long as the string
b
isn't mutated or destructed/deallocated while you're calling size()
, you're ok. It doesn't matter that myString()
might be updated to point to c
before/during/after your call to b
's .size()
.
Taking a step back, it can be tricky for the program to know how long after you call load()
you might try to dereference the pointer, and if the b
object is to later be mutated or destructed/deallocated, the kind of call you propose doesn't cooperate in any synchronisation around that later mutation/destruction. You can obviously add such coordination in myriad ways (e.g. some other atomic counter/flag, notifying the would-be modifier/destructor/deleter using a condition variable...), or you might decide to accept such a race condition sometimes (e.g. perhaps if b
is known to be one of the newest entries in a generously sized LRU cache).
If you're doing something like cycling myString
around a number of static const string
instances, you don't have to worry about all the mutation/destruction stuff above (well, not unless you're accessing them before/after main()
).
// B can I do this?
char myFifthChar = *(myString.load()->c_str() + 5);
Yes, with all the caveats above.
// C can I do this?
char myCharArray[255];
strcpy(myCharArray, myString.load()->c_str());
Yes, as above (and subject to the buffer provided being large enough).
I'm pretty sure C is illegal because myString might be deleted in the meantime.
As above - that concern's equally valid for all the 3 uses you've mentioned, just somewhat more likely for C because copying takes more CPU cycles to complete, and rather than get garbage values back losing a race could cause a buffer overrun.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With