C++ 无法读取共享内存
我试图通过共享内存发布一些随机的东西;出于某种奇怪的原因,读者没有读到发件人写的东西C++ 无法读取共享内存,c++,linux,g++,C++,Linux,G++,我试图通过共享内存发布一些随机的东西;出于某种奇怪的原因,读者没有读到发件人写的东西 #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:
#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;
}
};
我发现了几个问题,但是,我不确定他们是否能解决您的问题
shm\u open的名称
应以/
开头,以便便携使用
read
和publish
中,强制转换不能丢弃volatile
。例如:const uint64\u t newVal=*(uint64\u t volatile*)\u 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();
}
#2确实是个问题——编译器可能优化了
const uint64\u t newVal=*(uint64\u t*)\u ptr
。我想知道在哪一点上我可以停止使用volatile限定符,因为我认为声明volatile char*\u ptr
足以告诉编译器不要优化对\u ptr
的访问,因为\u ptr
有一个volatile限定符。希望你能分享一些光明。对于#1,为什么启动/可移植?谢谢@HCSF#1请参阅第二段。@HCSF#1:如果名称以字符开头,则使用相同名称值调用shm#u open()的进程引用相同的共享内存对象,只要该名称未被删除。@HCSF#2如果强制转换为(uint64#t volatile*)
在访问的任何地方都保持一致\u ptr
它也能按预期工作。但是std::atomic
是正确的方法。感谢您提供了一个示例。如果ptr指向C结构(而不是uint64 t),该怎么办<代码>自动p=静态强制转换(ptr);自动v=p->load()代码>然后访问字段v?如果S很大,load()可能会生成一个隐式锁,对吗?如果我坚持使用auto p=static\u cast(\u ptr)代码>,似乎不会生成隐式锁,对吗?只是想找到一个对延迟影响较小的解决方案。如果是,我是否也需要声明S volatile中的所有字段?当我访问ptr时,编译器似乎并不固有地尊重volatile
。谢谢
#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);
}
}
}
g++ (GCC) 7.2.1 20170829 (Red Hat 7.2.1-1)
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();
}
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.
}