我正在尝试使用在共享内存中实例化的缓冲区类。有一个唯一的写入器进程写入共享内存中的该对象,以及一个唯一的读取器(因此无需使用同步)。
有人能指出为什么从共享内存中读取是意外值吗?请注意,下面的源代码是使用 g++ 编译器在运行 Debian Linux 的 32 位机器上编译和测试的。
我编写了一个测试最小示例,文件如下所示。模板缓冲区类头文件:
// file testbuffer.h
#ifndef _TESTBUFFER_H_
#define _TESTBUFFER_H_
#include <iostream>
#include <cstring>
//our data type
typedef struct tagSTT{
int x;
float y;
char c;
} STT;
#define DATANUM 2048
template <typename T, int nCapacity >
class CBuff {
public:
CBuff ();
~CBuff ();
bool pop(T * pVal);
bool push(T const * const pVal);
private:
/*! memory buffer*/
T *m_pBuff;
T m_aBuff[nCapacity];
volatile int m_nCapacity;
//Read index. Always points to the item index right after the previously read. Initially = 0.
volatile int m_nR;
//Write index. Always points to the location right after the previously written to. Initially = 0.
volatile int m_nW;
};
template <typename T, int nCapacity >
CBuff<T, nCapacity>::CBuff () {
m_pBuff = NULL;
m_nCapacity = nCapacity;
m_nR = 0;
m_nW = 0;
m_pBuff = m_aBuff;
memset((void *)m_pBuff, 0, sizeof(T) * m_nCapacity);
}
template <typename T, int nCapacity >
CBuff<T, nCapacity>::~CBuff(){
}
template <typename T, int nCapacity >
bool CBuff<T, nCapacity>::pop(T * pVal) {
if (m_nR == m_nW){//nothing new to read
return false;
}
int nNextR = (m_nR + 1) % m_nCapacity;
(*pVal) = m_pBuff[m_nR];
m_nR = nNextR;
return true;
}
template <typename T, int nCapacity >
bool CBuff<T, nCapacity>::push(T const * const pVal){
int nNextW = (m_nW + 1) % m_nCapacity;
if (nNextW != m_nR) {//buffer is not full
m_pBuff[m_nW] = *pVal;
m_nW = nNextW;
return true;
}
return false;
}
#endif
接下来,这里是创建共享内存的程序文件,在该内存中实例化缓冲区,然后将一些测试数据启动到缓冲区中。
//Test program. *Only* writes to the shared memory buffer.
//Comile with:
// g++ -g -pedantic -Wall -I ./ fillbuff.cpp -o fillbuff -lrt
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <pthread.h>
#include <testbuffer.h>
int main(int argc, char ** argv) {
CBuff < STT, DATANUM> DBuff;//to get size of our whole data object
CBuff < STT, DATANUM> *pDBuff = NULL;
int fd = 0;
char ShmName[1024];
bzero(ShmName, sizeof(ShmName));
strcpy(ShmName, "/MyShm");
size_t ShmSize = sizeof(DBuff);
shm_unlink(ShmName);//incase it is lying around after a previous crash
fd = shm_open(ShmName, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd < 0){
return -10;
}
//set the size of the shared mem ob
if (ftruncate(fd, ShmSize) == -1){
return -11;
}
CBuff < STT, DATANUM> *pShm = NULL;
//map the file into the address space of the process
pShm = (CBuff < STT, DATANUM> *) mmap(0, ShmSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (pShm == (CBuff < STT, DATANUM> *)-1){
std::cerr << "ERROR mapping GUI shared memory" << std::endl;
return -12;
}
pDBuff = new (pShm)CBuff < STT, DATANUM>;
STT Data;
memset((void *)&Data, 0, sizeof(STT));
std::string sTmp;
int n = 0;
//start population data inout our buffer
for (n = 0; n < 29; n++) {
Data.x = n;
Data.y = float(n)/100;
Data.c = 'R';
std::clog << Data.x << " "
<< Data.y << " "
<< Data.c << std::endl;
if (pShm->push(&Data) == false){
std::cerr << "Could not push data sample " << n << " on to CB" << std::endl;
}
usleep(500000);//wait
}
pDBuff->~CBuff();
//unmap the memory
if (munmap(pShm, ShmSize) < 0){
std::cerr << "ERROR unmapping common memory" << std::endl;
return -20;
}
close (fd);
shm_unlink(ShmName);
return 0;
}
最后,这个必须在上述程序启动后启动的程序,从共享内存中读取值并打印出来。读取的值不是我保存在上面的缓冲区填充器中的值。我在这里想念什么?谢谢。
//Test program, *only* read from the shared memory buffer.
//compile with:
//g++ -g -Wall -I ./ emptybuff.cpp -o emptybuff.cpp -o emptybuff -lrt
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <pthread.h>
#include <testbuffer.h>
int main () {
char ShmName[1024];
bzero(ShmName, sizeof(ShmName));
strcpy(ShmName, "/MyShm");
size_t ShmSize = sizeof(CBuff < STT, DATANUM>);
int fd = shm_open(ShmName, O_RDWR, 0666);
if (fd < 0){
std::cerr << "Could not get a fd." << std::endl;
return -10;
}
CBuff < STT, DATANUM> *pBuff = NULL;
STT D;//will hold a sample
pBuff = (CBuff < STT, DATANUM> *) mmap(0, ShmSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (pBuff == (CBuff < STT, DATANUM> *) -1){
std::cerr << "Could not map shm" << std::endl;
return -1;
}
//read off the data from the buffer (which should already be filling up)
int k = 0;
for (k = 0; k < 10; k++) {
pBuff->pop(&D);//get a sample from the buffer
//print it out
std::clog << D.x << " "
<< D.y << " "
<< D.c << std::endl;
usleep(750000);//wait and lag behind the buffer filler process.
}
close (fd);
shm_unlink(ShmName);
return 0;
}