以下は、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;
}
最初に 1 つの端末でライター プログラムを実行します。
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