这是一个foo.c
将数据写入共享内存的程序。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
key_t key;
int shmid;
char *mem;
if ((key = ftok("ftok", 0)) == -1) {
perror("ftok");
return 1;
}
if ((shmid = shmget(key, 100, 0600 | IPC_CREAT)) == -1) {
perror("shmget");
return 1;
}
printf("key: 0x%x; shmid: %d\n", key, shmid);
if ((mem = shmat(shmid, NULL, 0)) == (void *) -1) {
perror("shmat");
return 1;
}
sprintf(mem, "hello");
sleep(10);
sprintf(mem, "exit");
return 1;
}
这是另一个bar.c
从同一共享内存中读取数据的程序。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
key_t key;
int shmid;
volatile char *mem;
if ((key = ftok("ftok", 0)) == -1) {
perror("ftok");
return 1;
}
if ((shmid = shmget(key, sizeof (int), 0400 | IPC_CREAT)) == -1) {
perror("shmget");
return 1;
}
printf("key: 0x%x; shmid: %d\n", key, shmid);
if ((mem = shmat(shmid, NULL, 0)) == (void *) -1) {
perror("shmat");
return 1;
}
printf("looping ...\n");
while (strncmp((char *) mem, "exit", 4) != 0)
;
printf("exiting ...\n");
return 0;
}
我首先在一个终端中运行编写器程序。
touch ftok && gcc foo.c -o foo && ./foo
当编写器程序仍在运行时,我在另一个终端中运行读取器程序。
gcc -O1 bar.c -o bar && ./bar
阅读器程序进入无限循环。看起来优化器已经优化了以下代码
while (strncmp((char *) mem, "exit", 4) != 0)
;
至
while (1)
;
因为它在循环中看不到任何可以在mem
读取一次后修改数据的内容。
但我正是出于这个原因宣布mem
的;volatile
以防止编译器对其进行优化。
volatile char *mem;
为什么编译器仍然优化读取mem
?
顺便说一句,我找到了一个可行的解决方案。有效的解决方案是修改
while (strncmp((char *) mem, "exit", 4) != 0)
;
至
while (mem[0] != 'e' || mem[1] != 'x' || mem[2] != 'i' || mem[3] != 't')
;
为什么编译器优化了,但即使声明在两种情况下strncmp((char *) mem, "exit", 4) != 0
都没有优化?mem[0] != 'e' || mem[1] != 'x' || mem[2] != 'i' || mem[3] != 't'
char *mem
volatile