gpt4 book ai didi

c++ - 读取共享内存失败

转载 作者:太空狗 更新时间:2023-10-29 22:55:33 25 4
gpt4 key购买 nike

我正在尝试通过共享内存发布一些随机的东西;出于某种奇怪的原因,读者没有看到发件人写的内容

#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <cstdio>

class SHM {
volatile char* _ptr;
public:
SHM() {
const auto handle = shm_open("myTest", O_RDWR|O_CREAT, 0666);
const auto size = 4 * 1024 * 1024;
if (-1 == ftruncate(handle, size)) {
throw;
}
_ptr = (volatile char*)mmap(0,size , PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0);

if(_ptr == MAP_FAILED){
throw;
}

int rc = fchmod(handle, 0666);
if (rc == -1) {
throw;
}
}

bool read(uint64_t& magic, uint64_t& time) {
const uint64_t newVal = *(uint64_t*)_ptr;
if (newVal != magic) {
magic = newVal;
printf("value changed!!!\n");
time = *(uint64_t*)(_ptr + sizeof(magic));
return true;
}
//printf("old value: %lu\n", newVal);
return false;
}

void publish(const uint64_t time) {
__sync_fetch_and_add((uint64_t*)_ptr, time);
__sync_synchronize();
*(uint64_t*)(_ptr + sizeof(uint64_t)) = time;
}
};

这是发件人:

#include <ctime>
#include <unistd.h>
#include <cstdlib>
#include <cstdint>
#include "shm.h"

int main() {
SHM shm;
timespec t;
for (auto i = 0; i < 10000; i++) {
if (0 == clock_gettime(CLOCK_REALTIME, &t)) {
const uint64_t v = t.tv_sec * 1000 * 1000 * 1000 + t.tv_nsec;
shm.publish(v);
printf("published %lu\n", v);
usleep(100);
}
}
}

这里是读者:

#include <iostream>
#include "shm.h"

int main() {
SHM shm;
uint64_t magic = 0;
uint64_t t = 0;
while (true) {
if (shm.read(magic, t)) {
printf("%lu, %lu\n", magic, t);
}
}
}

如果我重新启动阅读器,阅读器确实能够读取发送者写入的最后一个值。

但是,如果我先启动读取器,然后启动发送器,则发送器写入的所有值都不会被读取器接收。

更奇怪的是,如果我在 SHM::read() 中取消对 printf 语句的注释,那么读者有时可以理解。

有什么想法吗?

海湾合作委员会版本:

g++ (GCC) 7.2.1 20170829 (Red Hat 7.2.1-1)

最佳答案

我发现了几个问题,但是我不确定它们是否能解决您的问题。

    shm_open
  1. name 应该以 / 开头,以便于便携使用。
  2. readpublish 中,强制转换不得丢弃volatile。例如:const uint64_t newVal = *(uint64_t volatile*)_ptr;。更好的是,放弃 volatile 并使用 std::atomic

虽然涉及不同的进程,但仍然存在相同对象被多个执行线程访问并且这些线程中至少有一个修改了共享对象的情况。


我做了以上修改。使用 std::atomic 修复它:

class SHM {
void* _ptr;
public:
SHM() {
const auto handle = shm_open("/myTest", O_RDWR|O_CREAT, 0666);
const auto size = 4 * 1024 * 1024;
if (-1 == ftruncate(handle, size))
throw;

_ptr = mmap(0,size , PROT_READ | PROT_WRITE, MAP_SHARED, handle, 0);

if(_ptr == MAP_FAILED)
throw;
}

bool read(uint64_t& magic, uint64_t& time) {
auto p = static_cast<std::atomic<uint64_t>*>(_ptr);
const uint64_t newVal = p[0];
if (newVal != magic) {
magic = newVal;
printf("value changed!!!\n");
time = p[1];
return true;
}
return false;
}

void publish(const uint64_t time) {
auto p = static_cast<std::atomic<uint64_t>*>(_ptr);
p[0] += time;
p[1] = time;
}
};

void sender() {
SHM shm;
timespec t;
for (auto i = 0; i < 10000; i++) {
if (0 == clock_gettime(CLOCK_REALTIME, &t)) {
const uint64_t v = t.tv_sec * 1000 * 1000 * 1000 + t.tv_nsec;
shm.publish(v);
printf("published %lu\n", v);
usleep(100);
}
}
}

void reader() {
SHM shm;
uint64_t magic = 0;
uint64_t t = 0;
while (true) {
if (shm.read(magic, t)) {
printf("%lu, %lu\n", magic, t);
}
}
}

int main(int ac, char**) {
if(ac > 1)
reader();
else
sender();
}

使用 std::atomic 你可以有更多的控制。例如:

struct Data {
std::atomic<uint64_t> time;
std::atomic<uint64_t> generation;
};

// ...

bool read(uint64_t& generation, uint64_t& time) {
auto data = static_cast<Data*>(_ptr);

auto new_generation = data->generation.load(std::memory_order_acquire); // 1. Syncronizes with (2).
if(generation == new_generation)
return false;

generation = new_generation;
time = data->time.load(std::memory_order_relaxed);
printf("value changed!!!\n");
return true;
}

void publish(const uint64_t time) {
auto data = static_cast<Data*>(_ptr);

data->time.store(time, std::memory_order_relaxed);
data->generation.fetch_add(time, std::memory_order_release); // 2. (1) Synchronises with this store.
}

关于c++ - 读取共享内存失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51168908/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com