2

This question requires that two semaphores be used, one as a mutex, and one as a counting semaphore, and that the pair be used to simulate the interaction between students and a teacher's assistant.
I have been able to utilize the binary semaphore easily enough, however I cannot seem to find many examples that show the use of a counting semaphore, so I am quite sure I have it wrong, which is causing my code to not execute properly.
My code is below

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <semaphore.h>
#include <time.h>
#include <sys/types.h>

void *taThread();
void *student();

sem_t taMutex;
sem_t semaphore;

int main()
{
  pthread_t tid1;

  srand(time(NULL));

  sem_init(&taMutex,0,1);
  sem_init(&semaphore,1,3);

  pthread_create(&tid1, NULL, &taThread, NULL);
  pthread_join(tid1, NULL);
  return 0;
}


void *taThread()
{
  pthread_t tid2[10];
  int it = 0;

  printf("Teacher's Assistant taking a nap.\n");

  for (it =  0; it < 10; it ++)
  {
    pthread_create(&tid2[it], NULL, &student, NULL);
  }

  for (it = 0; it < 10; it ++)
  {
    pthread_join(tid2[it], NULL);
  }
}


void *student()
{
  int xTime;  
  xTime = rand() % 10 + 1;

  if (sem_wait(&taMutex) == 0)
  {
    printf("Student has awakened TA and is getting help. This will take %d       minutes.\n", xTime);
    sleep(xTime);
    sem_post(&taMutex);
  }
  else if (sem_wait(&semaphore) > 2 )
  {
    printf("Student will return at another time.\n");
  }
  else
  {
    sem_wait(&semaphore);

    printf("Student is working on their assignment until TA becomes available.\n");
    sem_wait(&taMutex);
    sem_post(&semaphore);
    printf("Student is entering the TA's office. This will take %d minutes", xTime);
    sleep(xTime);
    sem_post(&taMutex);
  }
}

My main question is: how can I get the threads to poll the counting semaphore concurrently?
I am trying to get a backup, with some students being forced to leave (or exit the thread) unhelped, with others waiting in the semaphore. Any assistance is appreciated, and any clarifications will be offered.

2
  • You get a +1 for a) Being honest that it is a homework question and b) You have at least attempted an answer Commented Dec 8, 2013 at 13:45
  • "polling" the semaphore? Do you mean sem_trywait? Commented Dec 8, 2013 at 13:47

1 Answer 1

2

I'm not sure if your class / teacher wants to make special distinctions here, but fundamentally, a binary semaphore is mostly equivalent to a copunting semaphore initialized to 1,1 so that when you count it down ("P") to zero it becomes "busy" (locked like a mutex) and when you release it ("V") it counts up to its maximum of 1 and it's now "un-busy" (unlocked). A counting semaphore typically starts with a higher initial value, typically for counting some resource (like 3 available chairs in a room), so that when you count it down there may still be some left. When you're done using the counted resource (e.g., when the "student" leaves the "TA's office") you count it back up ("V").

With POSIX semaphores, the call:

sem_init(&semaphore,1,3);

says that this is a process-shared semaphore (2nd argument nonzero), rather than a thread-shared semaphore; you don't seem to need that, and I'm not sure if some systems might give you an error—a failing sem_init call, that is—if &semaphore is not in a process-shared region. You should be able to just use 0, 3. Otherwise, this is fine: it's saying, in effect, that there are three "unoccupied chairs" in the "office".

Other than that, you'll need to either use sem_trywait (as @pilcrow suggested), sem_timedwait, or a signal to interrupt the sem_wait call (e.g., SIGALRM), in order to have some student who tries to get a "seat" in the "office" to discover that he can't get one within some time-period. Just calling sem_wait means "wait until there's an unoccupied chair, even if that takes arbitrarily long". Only two things stop this potentially-infinite wait: either a chair becomes available, or a signal interrupts the call.

(The return value from the various sem_* functions tells you whether you "got" the "chair" you were waiting for. sem_wait waits "forever", sem_trywait waits not-at-all, and sem_timedwait waits until you "get the chair" or the clock runs out, whichever occurs first.)


1The real difference between a true binary semaphore and a counting semaphore is that a binary semaphore doesn't offer you the ability to count. It's either acquired (and an acquire will block), or not-acquired (and an acquire will succeed and block other acquires). Various implementations may consider releasing an already-released binary semaphore a no-op or an error (e.g., runtime panic). POSIX just doesn't offer binary semaphores at all: sem_init initializes a counting semaphore and it's your responsibility to set it to 1, and not over-increment it by releasing when it's already released. See also comments below.

Sign up to request clarification or add additional context in comments.

4 Comments

"fundamentally, a counting semaphore is just a binary semaphore initialized to 1" I think you meant it the other way around.
@MichaelDorst well, sort of. I mean the two are internally mostly equivalent, though a binary semaphore can't be counted up past 1 (except in cheesy implementations where it can...). POSIX sem_init doesn't offer binary semaphores, only counting ones, so when you fake a binary semaphore with a POSIX semaphore, if you release it twice, it will just count to 2.
I know but I think you meant to say "a binary semaphore is just a counting semaphore initialized to 1". You just switched the words counting and binary, that's all I was indicating.
@MichaelDorst: Ah, I see. Will fix the wording (besides the footnote tweak I did yesterday).

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.