Reputation: 445
I want to create n processes running in parallel and have them lock a mutex, increment a counter, and then unlock and exit.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <pthread.h>
pthread_mutex_t mutex;
int main(int argc, char **argv) {
if (argc != 2)
return 0;
int n = atoi(argv[1]);
int i = 0;
int status = 0;
pthread_mutex_init(&mutex, NULL);
pid_t pid = 1;
static int *x;
x = mmap(NULL, sizeof *x, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
*x = 0;
printf("Creating %d children\n", n);
for(i = 0; i < n; i++) {
if (pid != 0)
pid = fork();
}
if (pid == 0) {
pthread_mutex_lock(&mutex);
*x = *x + 1;
printf("[CHLD] PID: %d PPID: %d X: %d\n", getpid(), getppid(), *x);
pthread_mutex_unlock(&mutex);
exit(0);
}
wait(&status);
printf("[PRNT] PID: %d X: %d\n", getpid(), *x);
munmap(x, sizeof *x);
return 0;
}
./procs 10000 however does not return with x=10000 I think this is because the mutex isn't shared between the processes, but what's the correct way to share the mutex?
Upvotes: 12
Views: 15437
Reputation: 11
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>
typedef struct {
pthread_mutex_t mutex;
int data;
}MUTEX_N_DATA;
int main(int argc, char **argv) {
if (argc != 2)
return 0;
int n = atoi(argv[1]);
int i = 0;
bool wait = true;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pid_t pid = 1;
MUTEX_N_DATA *x;
x = mmap(NULL, sizeof(MUTEX_N_DATA), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
x->data = 0;
pthread_mutex_init(&x->mutex, &attr);
printf("Creating %d children\n", n);
for(i = 0; i < n; i++) {
if (pid != 0) {
pid = fork();
printf("Created Child %d \n",pid);
}
}
if (pid == 0) {
pthread_mutex_lock(&x->mutex);
x->data = x->data + 1;
printf("[CHLD] PID: %d PPID: %d X: %d\n", getpid(), getppid(), x->data);
pthread_mutex_unlock(&x->mutex);
exit(0);
}
while(wait){
pthread_mutex_lock(&x->mutex);
if(x->data == n){
wait = false;
}
pthread_mutex_unlock(&x->mutex);
usleep(100000);
}
printf("[PRNT] PID: %d X: %d\n", getpid(), x->data);
munmap(x, sizeof *x);
return 0;
}
The wait() waits only until one of the child exits. with following changes it works.
https://man7.org/linux/man-pages/man2/fork.2.html
https://man7.org/linux/man-pages/man2/wait.2.html
Upvotes: 1
Reputation: 7092
Here's a port of my example in the comment using pthread_mutex
. First time I've done this, but seems to work:
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <stdbool.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <pthread.h>
typedef struct
{
bool done;
pthread_mutex_t mutex;
} shared_data;
static shared_data* data = NULL;
void initialise_shared()
{
// place our shared data in shared memory
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_SHARED | MAP_ANONYMOUS;
data = mmap(NULL, sizeof(shared_data), prot, flags, -1, 0);
assert(data);
data->done = false;
// initialise mutex so it works properly in shared memory
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&data->mutex, &attr);
}
void run_child()
{
while (true)
{
puts("child waiting. .. ");
usleep(500000);
pthread_mutex_lock(&data->mutex);
if (data->done) {
pthread_mutex_unlock(&data->mutex);
puts("got done!");
break;
}
pthread_mutex_unlock(&data->mutex);
}
puts("child exiting ..");
}
void run_parent(pid_t pid)
{
puts("parent sleeping ..");
sleep(2);
puts("setting done ..");
pthread_mutex_lock(&data->mutex);
data->done = true;
pthread_mutex_unlock(&data->mutex);
waitpid(pid, NULL, NULL);
puts("parent exiting ..");
}
int main(int argc, char** argv)
{
initialise_shared();
pid_t pid = fork();
if (!pid) {
run_child();
}
else {
run_parent(pid);
}
munmap(data, sizeof(data));
return 0;
}
Upvotes: 17