/* race.c Started by Jeff Ondich on 4/11/96 Last modified on 16 February 2022 This program demonstrates how race conditions can occur with shared memory. */ #include #include #include #include #include #include #include #define SHARED_INT_KEY ((key_t)1113) // Prototypes char *create_shared_mem(key_t, int); void interrupt_handler(int); void clean_up_shared_memory(); // global so interrupt_handler can detach it int *g_shared_integer; int main() { // This forces the parent and child to clean up their shared memory segments on Ctrl-C signal(SIGINT, interrupt_handler); g_shared_integer = (int *)create_shared_mem(SHARED_INT_KEY, sizeof(int)); if (g_shared_integer == NULL) { clean_up_shared_memory(); fprintf(stderr, "Trouble allocating shared memory\n"); exit(1); } // Fork a child process int pid = fork(); if (pid == -1) { perror("fork() failure"); exit(1); } if (pid != 0) { // Parent loops forever, putting 3's into the shared // integer using the (flawed) lock variable technique. fprintf(stderr, "Parent [%d] starting\n", getpid()); while (1) { *g_shared_integer = 3; } } else { // Child loops forever, putting 2's into the shared // integer using the lock variable technique. // If a race condition occurs, child reports it. fprintf(stderr, "Child [%d] starting\n", getpid()); long counter = 0; while (1) { counter++; *g_shared_integer = 2; if (*g_shared_integer != 2) { printf("Whoops %ld\n", counter); } } } return 0; } // Create a block of shared memory with the specified key. // create_shared_mem() also attaches the shared memory to // the current process' address space, and returns the // attached address. Returns NULL if errors occur. char *create_shared_mem(key_t key, int size) { int id; char *shared_memory_address; // Allocate the shared memory id = shmget(key, size, 0664 | IPC_CREAT | IPC_EXCL); if (id == -1) { perror("shmget trouble"); return NULL; } // Attach the shared memory to the address space of the current process shared_memory_address = (char *)shmat(id, (char *)0, 0); if (shared_memory_address == (char *)-1) { perror("shmat trouble"); return NULL; } return shared_memory_address; } void clean_up_shared_memory() { int id = shmget(SHARED_INT_KEY, 0, 0); shmctl(id, IPC_RMID, NULL); shmdt(g_shared_integer); } void interrupt_handler(int sig) { fprintf(stderr, "%d quitting\n", getpid()); clean_up_shared_memory(); exit(1); }