testing共享内存,奇怪的事情发生

我有在RedHat 5.5中运行的4.1.2编译的2个程序,testing共享内存shmem1.c是一个简单的工作,如下所示:

#define STATE_FILE "/program.shared" #define NAMESIZE 1024 #define MAXNAMES 100 typedef struct { char name[MAXNAMES][NAMESIZE]; int heartbeat ; int iFlag ; } SHARED_VAR; int main (void) { int first = 0; int shm_fd; static SHARED_VAR *conf; if((shm_fd = shm_open(STATE_FILE, (O_CREAT | O_EXCL | O_RDWR), (S_IREAD | S_IWRITE))) > 0 ) { first = 1; /* We are the first instance */ } else if((shm_fd = shm_open(STATE_FILE, (O_CREAT | O_RDWR), (S_IREAD | S_IWRITE))) < 0) { printf("Could not create shm object. %s\n", strerror(errno)); return errno; } if((conf = mmap(0, sizeof(SHARED_VAR), (PROT_READ | PROT_WRITE), MAP_SHARED, shm_fd, 0)) == MAP_FAILED) { return errno; } if(first) { for(idx=0;idx< 1000000000;idx++) { conf->heartbeat = conf->heartbeat + 1 ; } } printf("conf->heartbeat=(%d)\n",conf->heartbeat) ; close(shm_fd); shm_unlink(STATE_FILE); exit(0); }//main 

和shmem2.c一样如下:

 #define STATE_FILE "/program.shared" #define NAMESIZE 1024 #define MAXNAMES 100 typedef struct { char name[MAXNAMES][NAMESIZE]; int heartbeat ; int iFlag ; } SHARED_VAR; int main (void) { int first = 0; int shm_fd; static SHARED_VAR *conf; if((shm_fd = shm_open(STATE_FILE, (O_RDWR), (S_IREAD | S_IWRITE))) < 0) { printf("Could not create shm object. %s\n", strerror(errno)); return errno; } ftruncate(shm_fd, sizeof(SHARED_VAR)); if((conf = mmap(0, sizeof(SHARED_VAR), (PROT_READ | PROT_WRITE), MAP_SHARED, shm_fd, 0)) == MAP_FAILED) { return errno; } int idx ; for(idx=0;idx< 1000000000;idx++) { conf->heartbeat = conf->heartbeat + 1 ; } printf("conf->heartbeat=(%d)\n",conf->heartbeat) ; close(shm_fd); exit(0); } 

编译之后:

  gcc shmem1.c -lpthread -lrt -o shmem1.exe gcc shmem2.c -lpthread -lrt -o shmem2.exe 

和两个terminal几乎同时运行两个程序:

  [test]$ ./shmem1.exe First creation of the shm. Setting up default values conf->heartbeat=(840825951) [test]$ ./shmem2.exe conf->heartbeat=(1215083817) 

我感到困惑! 因为shmem1.c是一个循环10亿次,怎么能有840,825,951这样的答案呢?

我这样运行shmem1.exe和shmem2.exe,大部分的结果是conf-> heartbeat会大于10亿,但很less随机,我会看到结果conf-> heartbeat会小于10亿,
无论是在shmem1.exe或shmem2.exe!

如果只运行shmem1.exe,总是打印10亿,我的问题是什么原因conf-> heartbeat =(840825951)在shmem1.exe中?

更新:虽然不是很确定,但是我想我弄明白了是怎么回事,如果shmem1.exe运行10次例如conf-> heartbeat = 10,这时shmem1.exerest一下然后回来,shmem1 .exe从共享内存读取并conf-> heartbeat = 8,所以shmem1.exe会从8继续,为什么conf-> heartbeat = 8? 我认为这是因为shmem2.exe更新共享内存数据为8,shmem1.exe没有写10回到共享内存才rest….这只是我的理论…我不知道如何certificate它!

你回来的值表明你没有增加原子的共享内存。 以下循环:

 int idx ; for(idx=0;idx< 1000000000;idx++) { conf->heartbeat = conf->heartbeat + 1 ; } 

归结为:

 int idx ; for(idx=0;idx< 1000000000;idx++) { // read int heartbeat= conf->heartbeat; // write conf->heartbeat = heartbeat + 1 ; } 

在读写评论之间,一个进程可以被换出来让另一个进程运行。 如果shmem1.exe和shmem2.exe都运行,这意味着您可以让shmem1.exe在shmem2.exe读取和写入conf->heartbeat之间多次增加conf->heartbeat ,反之亦然。

如果你想要一致的更新,你需要使用你的平台的原子内存增量功能。 这保证了读取/修改/写入操作总是导致增加值,而不是可能回写陈旧的值。

例如,shmem1.exe和shmem2.exe之间没有任何同步,你可能会有shmem1.exe和shmem2.exe这两个病态输出2

 shmem1.exe: read 0 shmem2.exe: read 0 // shmemem2.exe goes to sleep for a loooong time shmem1.exe: write 1 // ... shmem1.exe keeps running shmem1.exe: write 999,999,999 // shmem2.exe wakes up shmem2.exe write 1 shmem2.exe read 1 // shmem2.exe goes back to sleep shmem1.exe read 1(!) // shmem1.exe goes to sleep // shmem2.exe wakes up shmem2.exe write 2 shmem2.exe read 2 shmem2.exe write 3 // shmem2.exe continues, shmem1.exe stays asleep shmem2.exe read 999,999,999 shmem2.exe write 1,000,000,000 // shmem2.exe goes to sleep, shmem1.exe wakes up shmem1.exe write 2(!) shmem1.exe read 2 shmem1.exe print 2 //shmem2.exe wakes up shmem2.exe read 2 shmem2.exe print 2 

这可能发生在没有CPU重新排序,只是安排疯狂。