My use case
I have a program that manages a large number of data records, each of which with the size of R
bytes. Each record has a lock whose size is 4 bytes. So in total, each record takes up S = R + 4
bytes. These records have to be laid in memory next to each other due to application-specific reasons, as illustrated below:
.-------------------------------------------------------------------------------.
| lock_1 | data_1 | lock_2 | data_2 | ........... | lock_n | data_n |
.-------------------------------------------------------------------------------.
On the c++ level, my program allocates a contiguous memory block, in the form of a char array. The array is cache line aligned, and R
is a multiple of 4, effectively making each lock to be properly aligned:
char* region = new char[S*N]; // N is the number of records
Question
How can I use std::atomic
functions to atomically modify the locks, without actually having to maintain an array of std::atomic<int>
objects. I can think of two solutions:
- Given that Linux kernel uses identical bitwise representation for
int
andstd::atomic<int>
, cast a pointer of a lock tostd::atomic
, e.g.:
char* x = region + (lockID * S); reinterpret_cast<atomic<int>*>(x)->fetch_add(1);
, wherex
is the memory location of a given lock. - If the above solution is not correct (perhaps because it may mess up the static code analysis done by the compiler), actually define a lock as an atomic value using placement new:
for (int lockID = 0; lockID < N; lockID++) { char* memoryOffset = region + (lockID * S); std::atomic<int>* lockPtr = new (memoryOffset) std::atomic<int>; }
Here, I do not want to keep an array oflockPtr
s, due to space considerations, so I throw them away, and use the cast from solution 1 to get the pointer to the atomic object of a given lock.
Is any of these solutions correct? If not, what is the right solution?
Aucun commentaire:
Enregistrer un commentaire