Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

procs, fork(), and mutexes

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?

like image 763
user1743798 Avatar asked Oct 04 '13 03:10

user1743798


People also ask

What do mutexes do?

In computer programming, a mutex (mutual exclusion object) is a program object that is created so that multiple program thread can take turns sharing the same resource, such as access to a file.

Can you have multiple mutexes?

If you have more than one mutex, each mutex is independent: a thread can hold neither, one or both of them. In your Reader , a thread first acquires mutex .

What are mutexes in C?

A Mutex is a lock that we set before using a shared resource and release after using it. When the lock is set, no other thread can access the locked region of code.

Do mutexes work across processes?

Mutexes can synchronize threads within the same process or in other processes. Mutexes can be used to synchronize threads between processes if the mutexes are allocated in writable memory and shared among the cooperating processes (see mmap(2)), and have been initialized for this task.


1 Answers

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;
}
like image 56
goji Avatar answered Oct 03 '22 20:10

goji