Quantcast
Viewing all articles
Browse latest Browse all 3

Do I use atomic over shared memory correctly here

Suppose we have two processes.

Both use same mmap-ed memory region in order to pass some information, in this case uint16_t.

I read all kind of opinions why std::atomic<> should work, if it uses is_always_lock_free.

So I did this code. Code works as expected, but is this code thread / inter-process safe:

#include <cstdint>#include <atomic>#include <iostream>#include <sys/mman.h>#include <fcntl.h>#include <unistd.h> // sleep#include <time.h>using I  = uint16_t;using AI = std::atomic<I>;static_assert(std::atomic<I>::is_always_lock_free);constexpr size_t SIZE = sizeof(AI);constexpr const char *NAME = "nmmm";constexpr I STOP = 12345;void error(const char *msg){    std::cout << msg << '\n';    exit(10);}int main(int argc, const char **argv){    std::cout << sizeof(I) << ''<< sizeof(AI) << '\n';    int fd = shm_open(NAME,  O_RDWR | O_CREAT, 0644);    if (fd < 0)        error("shm_open");    int t = ftruncate(fd, SIZE);    if (t < 0)        error("ftruncate");    void *vmem = mmap(nullptr, SIZE, PROT_WRITE, MAP_SHARED, fd, 0);    if (vmem == MAP_FAILED)        error("mmap");    std::cout << "All set up!" << ''<< vmem << '\n';    AI *ai = reinterpret_cast<AI *>(vmem);    if (argc > 1){        switch(argv[1][0]){        case 'g':        case 'G':            ai->store(0, std::memory_order_relaxed);            while(true){                auto x = ai->load(std::memory_order_relaxed);                std::cout << x << '\n';                if (x == STOP)                    break;                sleep(1);            }        case 's':        case 'S':            ai->store(STOP, std::memory_order_relaxed);            break;        default:            {                srand(time(nullptr));                I const x = rand() & 0xFFFF;                std::cout << "set val to " << x << '\n';                ai->store(x , std::memory_order_relaxed);            }            break;        }    }    munmap(vmem, SIZE);//  shm_unlink(NAME);}

Excuse my mixing of C and C++ like using rand.

What you suppose to do it -

# console 1./a.out g # start "Getter"# console 2./a.out x # set random value# or./a.out s # set "Stop" value, so process in console 1 stops.

What I am worrying:

  • no placement new, just reinterpret cast + initial value set.
  • not a d-tor either.
  • why sizeof(uint16_t) is same as sizeof(std::atomic<uint16_t>) - is it always like this if is_always_lock_free ? Is std::atomic just a fancy Assembly instruction?

Update

It appears, std::atomic<uint16_t> is POD. So casting is not UB (undefined behavour)

static_assert(std::is_pod_v<std::atomic<uint16_t> >);

Also it appears std::atomic<uint16_t> operations compiles to single assembly instructions:

https://gcc.godbolt.org/z/d6bK9jfza


Viewing all articles
Browse latest Browse all 3

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>