Diwakar Sharma
Diwakar Sharma

Reputation: 425

Sem_wait() not blocking after first true condition

I am learning to use semaphores and below is a small scenario which I've tried to implement. Its behaving weird in a way. After sem_wait() gets unblocked first time, its not getting blocked again and keeps on looping, not getting why. Is this the right way or right scenario to use semaphore?

EDIT: I just realized that if I uncomment the sleep after sem_post, it works fine. .Reason being it was repeatedly doing sem_post() before thread could do coin=0 I believe. But is it right to use sleep this way with semaphores. I believe this would be considered a bad practice?

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>


#define MAX_MSG_LEN  256

sem_t sem1;
sem_t sem2;
int coin=0;

void *thrdFun1(void *arg);
void *thrdFun2(void *arg);
void toggleCase(char *buf, int cnt);

int main()
{
    pthread_t thrd1;
    char argmsg1[] = "Thread1: Waiting to deliver\n";
    int thNum;
    int res;

    res = sem_init(&sem1, 0,0);     
//  res = sem_init(&sem2, 0,0);     

    res = pthread_create(&thrd1, NULL, thrdFun1, argmsg1);      

    while(1)
    {
    if (coin==0)
        {
        printf("no coin: please enter coin\n"); 
        scanf("%d",&coin);
        }
    else
        {
        sem_post(&sem1);
//      sleep(1);
        }
    }

    return 0;
}

void *thrdFun1(void *arg)
{
    while(1)
    {
        printf("I'm %s\n",(char *)arg);

    sem_wait(&sem1);

    printf("Delivered...\n");
    coin=0;
    sleep(1);
    }
}       

Upvotes: 0

Views: 3427

Answers (4)

VoidPointer
VoidPointer

Reputation: 3107

You realized it right, it is repeatedly doing sem_post() before thread could do coin=0 when removing all sleeps.

To solve this you could use second semaphore (you already tried it seems) like below,

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>

#define MAX_MSG_LEN  256


sem_t sem1;
sem_t sem2;
int coin=0;

void *thrdFun1(void *arg);
void *thrdFun2(void *arg);
void toggleCase(char *buf, int cnt);

int main()
{
    pthread_t thrd1;
    char argmsg1[] = "Thread1: Waiting to deliver\n";
    int thNum;
    int res;

    res = sem_init(&sem1, 0,0);
    res = sem_init(&sem2, 0,0);

    res = pthread_create(&thrd1, NULL, thrdFun1, argmsg1);

    while(1)
    {
            if (coin==0)
            {
                    printf("no coin: please enter coin\n");
                    scanf("%d",&coin);
            }
            else
            {
                    sem_post(&sem1);    // Coin is spun
                    sem_wait(&sem2);    // Wait till it is caught 
            }
    }

    return 0;
}

void *thrdFun1(void *arg)
{
    while(1)
    {
            printf("I'm %s\n",(char *)arg);

            sem_wait(&sem1);    // Wait to spin the coin
            coin=0;
            sem_post(&sem2);    // inform as caught

            printf("Delivered...\n");
    }
}

Upvotes: 1

Mayur Navadia
Mayur Navadia

Reputation: 241

there is a chance that "Thread1: Waiting to deliver" this string can get printed many times.

What you are trying to achieve is looks like producer-consumer problem.

You required two semaphore to achive this.

main function:

while(1)
    {
    if (coin==0)
        {
        printf("no coin: please enter coin\n"); 
        scanf("%d",&coin);
        }
    else
        {
        sem_post(&sem1);
        sem_wait(&sem2) 
        }
    }

in thread function

while(1)
    {
        printf("I'm %s\n",(char *)arg);

        sem_wait(&sem1);

        printf("Delivered...\n");
        coin=0;
        sem_post(&sem2)
    }

Upvotes: 0

Binayaka Chakraborty
Binayaka Chakraborty

Reputation: 1335

Semaphores are used to control Critical-Section Access. In this case, critical section would be the output shell. The thread may or may not start promptly when the pthread_create() is called. Also, sem_wait() will decrease the value of sem1 with each call. Thus, when you include sleep(1) in the thrdFun1 function, there may be undefined behaviour :)

Upvotes: 3

Dayal rai
Dayal rai

Reputation: 6606

You need to remove sleep(1); from function thrdFun1. After this there will not be any need of sleep(1) in main.

Upvotes: 1

Related Questions