无法读取共享内存

时间:2018-07-04 08:16:01

标签: 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:
    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语句的注释,那么读者有时就可以使用。

有什么主意吗?

GCC版本:

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

1 个答案:

答案 0 :(得分:1)

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

    对于import cv2 import numpy as np import math img = cv2.imread('angle.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, threshold = cv2.threshold(gray,170,255,cv2.THRESH_BINARY) im, contours, hierarchy = cv2.findContours(threshold,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) for c in contours: area = cv2.contourArea(c) perimeter = cv2.arcLength(c, False) if area < 10001 and 100 < perimeter < 1000: # first approach - fitting line and calculate with y=kx+n --> angle=tan^(-1)k rows,cols = img.shape[:2] [vx,vy,x,y] = cv2.fitLine(c, cv2.DIST_L2,0,0.01,0.01) lefty = int((-x*vy/vx) + y) righty = int(((cols-x)*vy/vx)+y) cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2) (x1, y1) = (cols-1, righty) (x2, y2) = (0, lefty) k = (y2-y1)/(x2-x1) angle = math.atan(k)*180/math.pi print(angle) #second approch - cv2.minAreaRect --> returns center (x,y), (width, height), angle of rotation ) rect = cv2.minAreaRect(c) box = cv2.boxPoints(rect) box = np.int0(box) cv2.drawContours(img,[box],0,(0,0,255),2) print(rect[2]) cv2.imshow('img2', img)
  1. name应该以{{1​​}}开头,以供便携式使用。
  2. shm_open/中,强制类型转换不能丢弃read。例如:publish。更好的是,放下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();
}