|
#include <errno.h> |
|
#include <pthread.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <sys/mman.h> |
|
#include <sys/wait.h> |
|
#include <unistd.h> |
|
|
|
struct shared_data |
|
{ |
|
unsigned int counter; |
|
pthread_mutex_t mutex; |
|
}; |
|
|
|
void child_loop(struct shared_data *shared) |
|
{ |
|
for (int i = 0; i < 100; ++i) { |
|
pthread_mutex_lock(&shared->mutex); |
|
unsigned int old_counter_value = shared->counter; |
|
// Sleep up to 100ms |
|
usleep(rand() % (100 * 1000)); |
|
shared->counter = old_counter_value + 1; |
|
pthread_mutex_unlock(&shared->mutex); |
|
} |
|
} |
|
|
|
int main() |
|
{ |
|
// Create shared data section using anonymous mmap. |
|
struct shared_data *shared = (struct shared_data*)mmap( |
|
NULL, |
|
sizeof(struct shared_data), |
|
PROT_READ | PROT_WRITE, |
|
MAP_SHARED | MAP_ANONYMOUS, |
|
-1, |
|
0); |
|
if (shared == MAP_FAILED) { |
|
printf("mmap failed\n"); |
|
return 1; |
|
} |
|
|
|
// Initialise the shared data, and its mutex. |
|
shared->counter = 0; |
|
pthread_mutexattr_t mutexattr; |
|
if (pthread_mutexattr_init(&mutexattr) != 0) { |
|
printf("pthread_mutexattr_init failed\n"); |
|
return 1; |
|
} |
|
if (pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED) != 0) { |
|
printf("pthread_mutexattr_setpshared failed\n"); |
|
return 1; |
|
} |
|
if (pthread_mutex_init(&shared->mutex, &mutexattr) != 0) { |
|
printf("pthread_mutex_init failed\n"); |
|
return 1; |
|
} |
|
|
|
// Create five child processes using the shared data. |
|
for (int i = 0; i < 5; ++i) { |
|
pid_t ret = fork(); |
|
if (ret < 0) { |
|
printf("fork failed\n"); |
|
} else if (ret == 0) { |
|
printf("running child...\n"); |
|
child_loop(shared); |
|
printf("child done\n"); |
|
// Important to terminate here, not exit the loop in children. |
|
return 0; |
|
} else { |
|
printf("created child %d\n", ret); |
|
} |
|
} |
|
|
|
// Wait until there are no more children. |
|
printf("parent waiting for children...\n"); |
|
while (1) { |
|
pid_t ret = wait(0); |
|
if (ret < 0) { |
|
if (errno != ECHILD) { |
|
printf("unexpected error from wait: %s\n", strerror(errno)); |
|
} |
|
break; |
|
} |
|
printf("child %d terminated\n", ret); |
|
} |
|
|
|
// Finally, print the final counter result. |
|
printf("final value of counter: %d\n", shared->counter); |
|
|
|
return 0; |
|
} |