Multi-process vs Multi-thread

104 Views Asked by At

I have been trying to measure the runtime of the same task using multi processes and multi threads. I was expecting to see that the threads approach is faster because thread context switch is faster than process switch.

The task is to create 3 elements (processes / threads) and print from 1 to 1,000,000 with each of them. Am I doing anything wrong here?

Process approach code:

#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#include <semaphore.h>
#include <fcntl.h>

sem_t mutex;

int main() {
    int i;
    int N = 1;
    close(STDOUT_FILENO);
    open("multiproc.txt", O_WRONLY | O_CREAT, 0666);
    sem_init(&mutex, 1, 1);
    for(i=0; i<2; i++) {
        pid_t child_pid = fork();
        if(child_pid == 0) {
            N = i + 2;
            break;
        }
    }
    for(i=1; i<=1000000; i++) {
        sem_wait(&mutex);
        printf("Element: %d : %d\n", N, i);
        sem_post(&mutex);
    }
    if(N == 1) {
        while (wait(NULL) > 0);
        sem_destroy(&mutex);
        close(STDOUT_FILENO);
    }
    return 0;
}

Thread approach code:

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <fcntl.h>

sem_t mutex;

void* mythread(void* arg) {
    int n = *(int*)arg;
    int i;
    for(i = 1; i <= 1000000; i++) {
        sem_wait(&mutex);
        printf("Element: %d : %d\n", n, i);
        sem_post(&mutex);
    }
}

int main(void) {
    close(STDOUT_FILENO);
    open("multithread.txt", O_WRONLY | O_CREAT, 0666);
    sem_init(&mutex, 0, 1);
    pthread_t thr[3];
    for(int n = 0; n < 3; n++)
        pthread_create(&thr[n], NULL, mythread, &n);
    for(int n = 0; n < 3; n++)
        pthread_join(thr[n], NULL);
    sem_destroy(&mutex);
    close(STDOUT_FILENO);
}

I used semaphores and compiled with gcc -pthread and -lrt flags.

The times measured are:

abcd@abcd-Virtual-Machine:~/Desktop$ time ~/Desktop/multiproc

real    0m0.173s
user    0m0.281s
sys 0m0.047s
abcd@abcd-Virtual-Machine:~/Desktop$ time ~/Desktop/multithread

real    0m1.186s
user    0m0.664s
sys 0m1.489s
1

There are 1 best solutions below

6
ikegami On

From my system's sem_init map page,

If pshared is nonzero, then the semaphore is shared between processes, and should be located in a region of shared memory

You did not place the semaphore in memory that is shared between the processes as required. As such, each of your processes ends up with a different semaphore (a clone of the first), so the semaphores provide no mutual exclusion, so your processes never wait.

for(i=1; i<=1000000; i++) {
    sem_wait(&mutex);
    fprintf(stderr, "%u lock\n", getpid());       // Added
    printf("Element: %d : %d\n", N, i);
    fprintf(stderr, "%u unlock\n", getpid());     // Added
    sem_post(&mutex);
}
$ ./multiproc
251 lock
249 lock      <-- Both 249 and 251 are in the mutual exclusion area
251 unlock
251 lock
...

Updated multiproc.c:

#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/mman.h>                      // Added

sem_t *mutex;                              // Now a pointer.

int main() {
    int i;
    int N = 1;
    close(STDOUT_FILENO);
    open("multiproc.txt", O_WRONLY | O_CREAT, 0666);

    mutex = mmap(                          // Added
        NULL,
        sizeof(*mutex),
        PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS,
        -1,
        0
    );

    sem_init(mutex, 1, 1);
    for(i=0; i<2; i++) {
        pid_t child_pid = fork();
        if(child_pid == 0) {
            N = i + 2;
            break;
        }
    }
    for(i=1; i<=1000000; i++) {
        sem_wait(mutex);
        printf("Element: %d : %d\n", N, i);
        sem_post(mutex);
    }
    if(N == 1) {
        while (wait(NULL) > 0);
        sem_destroy(mutex);
        munmap(mutex, sizeof(*mutex));     // Added
        close(STDOUT_FILENO);
    }
    return 0;
}

Updated results:

$ time ./multiproc

real    0m0.705s
user    0m0.529s
sys     0m0.906s

$ time ./multithread

real    0m0.784s
user    0m0.626s
sys     0m0.832s