/* * shared_mutex: Mutex in mmap memory shared between processes. * * Ben Cohen, July 2017. * * Compile using: * gcc -o shared_mutex shared_mutex.c -ggdb -Wall -std=c99 -pthread * * Two processes are created with an mmap shared memory region * containing an array of chars and a mutex. The mutex is created with * the attribute PTHREAD_PROCESS_SHARED. * * One process writes increasing numbers into an array and the other * prints the contents once a second. * * By default the mutex will prevent the first process updating while * the second is reading so all the value in each row will be the same, * for example: * * 0 0 0 0 0 0 0 0 0 0 * 79 79 79 79 79 79 79 79 79 79 * 209 209 209 209 209 209 209 209 209 209 * 122 122 122 122 122 122 122 122 122 122 * 106 106 106 106 106 106 106 106 106 106 * ... * * If invoked with the argument --no-mutex then it does not obtain the * mutex so the values are modified while the second process reads the * array and the values in each row will not all be the same: * * 130 206 230 236 241 247 253 3 12 20 * 16 22 28 34 39 45 51 57 63 69 * 196 186 193 200 206 211 217 223 228 234 * 133 104 112 118 123 128 133 138 144 150 * 136 111 116 122 128 133 138 143 149 154 * ... */ #define _BSD_SOURCE #include #include #include #include #include #include #include #include #include #define MMAP_NAME "/tmp/mmaptest" #define LENGTH sizeof(struct mapped) #define ARRAY_ELEMENTS 10 struct mapped { unsigned char array[ARRAY_ELEMENTS]; int use_mutex; pthread_mutex_t mutex; }; void die(char *msg) { perror(msg); exit(1); } void child(struct mapped *mapping) { unsigned int n = 0; while (1) { if (mapping->use_mutex) pthread_mutex_lock(&mapping->mutex); for (int i = 0; i < 10; i ++) { mapping->array[i] = n; } n ++; if (mapping->use_mutex) pthread_mutex_unlock(&mapping->mutex); } } void parent(struct mapped *mapping) { while (1) { if (mapping->use_mutex) pthread_mutex_lock(&mapping->mutex); for (int i = 0; i < 10; i ++) { printf("%4d", mapping->array[i]); } printf("\n"); if (mapping->use_mutex) pthread_mutex_unlock(&mapping->mutex); sleep(1); } } int main(int argc, char **argv) { int rc; unlink(MMAP_NAME); int fd = open(MMAP_NAME, O_CREAT|O_RDWR, 00600); if (fd == -1) die("open"); rc = ftruncate(fd, LENGTH); if (rc != 0) die("ftruncate"); struct mapped *mapping = (struct mapped *)mmap(NULL, LENGTH, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (mapping == MAP_FAILED) die("mmap"); close(fd); pthread_mutexattr_t mutexattr; rc = pthread_mutexattr_init(&mutexattr); if (rc != 0) die("pthread_mutexattr_init"); rc = pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED); if (rc != 0) die("pthread_mutexattr_setpshared"); pthread_mutex_init(&mapping->mutex, &mutexattr); if (rc != 0) die("pthread_mutex_init"); if (argc >= 2 && strcmp(argv[1], "--no-mutex") == 0) mapping->use_mutex = 0; else mapping->use_mutex = 1; switch (fork()) { case -1: die("fork"); case 0: child(mapping); break; default: parent(mapping); break; } rc = munmap(mapping, LENGTH); if (rc != 0) die("munmap"); return 0; }