Here is a program foo.c
that writes data to shared memory.
#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;
}
Here is another program bar.c
that reads data from the same shared memory.
#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;
}
I run the writer program first in one terminal.
touch ftok && gcc foo.c -o foo && ./foo
While the writer program is still running, I run the reader program in another terminal.
gcc -O1 bar.c -o bar && ./bar
The reader program goes into an infinite loop. It looks like the optimizer has optimized the following code
while (strncmp((char *) mem, "exit", 4) != 0)
;
to
while (1)
;
because it sees nothing in the loop that could modify the data at mem
after it has been read once.
But I declared mem
as volatile
precisely for this reason; to prevent the compiler from optimizing it away.
volatile char *mem;
Why does the compiler still optimize away the reads for mem
?
By the way, I have found a solution that works. The solution that works is to modify
while (strncmp((char *) mem, "exit", 4) != 0)
;
to
while (mem[0] != 'e' || mem[1] != 'x' || mem[2] != 'i' || mem[3] != 't')
;
Why is it that the compiler optimizes away strncmp((char *) mem, "exit", 4) != 0
but does not optimize away mem[0] != 'e' || mem[1] != 'x' || mem[2] != 'i' || mem[3] != 't'
even though char *mem
is declared to be volatile
in both cases?