2
\$\begingroup\$

This is my first time using semaphores and I was wondering if I implemented them to the best of their abilities in my code....

#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include<semaphore.h>
#include <math.h>

#define NR_THREAD 2

int sum=0;
unsigned int seed;
sem_t sem0;


void* func0(void *param) {
    int tmp;
    int i;
    for(i=0; i<10; i++) {
        sem_wait (&sem0);
        tmp=sum;
        tmp++;
        if(rand_r(&seed)%2) {
            printf("sleeping for 1 sec\n");
            sleep(1);
        } else {
            printf("sleeping for 2 sec\n");
            sleep(2);
        }
        sem_post (&sem0);
        sem_wait (&sem0);
        sum=tmp;
        if(rand_r(&seed)%2) {
            printf("sleeping for 1 sec\n");
            sleep(1);
        } else {
            printf("sleeping for 2 sec\n");
            sleep(2);
        }
        sem_post (&sem0);
    }

    return (void*)0;
}

int main() {
    int i;
    int error;
    pthread_t *tid;
    pthread_attr_t attr;

    seed=(unsigned int)time(NULL);

    if((tid=(pthread_t*)calloc(NR_THREAD, sizeof(pthread_t)))==NULL) {
        fprintf(stderr, "calloc() failed\n");
        exit(1);
    }
    sem_init(&sem0, 0, 1);
    if(sem_init(&sem0, 0, 1)==-1) {
        perror("Failed to sem_init() sem0");
        exit(1);
    }

    pthread_attr_init(&attr);
    for(i=0; i<NR_THREAD; i++) {
        if((error=pthread_create(&tid[i], &attr, func0, 
            (void*)0))) {
            fprintf(stderr, "pthread_create() failed: %d %d\n", 
                i, error);
            tid[i]=pthread_self();
        }
    }

    for(i=0; i<NR_THREAD; i++) {
        if(pthread_equal(pthread_self(), tid[i]))
            continue;

        if((error = pthread_join(tid[i], NULL))) {
            fprintf(stderr, "pthread_join() failed: %d %d\n", 
                i, error);
        }
    }

    printf("Final sum= %d\n", sum);

    free(tid);

    if(sem_destroy(&sem0)==-1) {
        perror("Failed to sem_destroy() sem0");
        exit(2);
    }

    return 0;
}

It runs and gets the correct answer, but I was wondering if there were better places to put them or not. Also, I'm getting a warning, I'm receiving an implicit declaration warning on if(rand_r(&seed)%2) { and I'm not sure how to go about fixing this problem.

This is a demo in which two threads each sleep 10 times.

\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

I presume that you expected the result to be 20. Unfortunately this code may produce anything from 2 to 20.

Here is a scenario how 2 can be produced:

thread 1 grabs the semaphore (its tmp becomes 1)
thread 1 posts the semaphore in the mid-loop

thread 2 grabs the semaphore (sum is still 0)
thread 2 runs the loop for 9 times (sum becomes 9)
thread 2 posts the semaphore at the loop end

thread 1 takes over and completes its first loop
sum becomes 1
thread 1 posts the semaphore at the loop end

thread 2 takes over; its tmp becomes 2
thread 2 posts the semaphore in the mid-loop

thread 1 takes over and runs to completion

thread 2 (its tmp still 2) completes the second half of the loop
sum becomes 2

In your code the threads sleep while holding the semaphore (so sleeping is pretty much irrelevant). Contexts may only switch in the tiny window between sem_post and sem_wait. Most likely it never happens (scheduler doesn't have to switch threads), which explains why you are getting 20. Try to increase the window, say

    sem_post();
    sleep();
    sem_wait();

and see what happens.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.