Thursday 6 September 2012

Pthread Library Part:2

Prerequisites: Read the part 1 of pthread library :) :)

In my previous post, I have explained about the mutexes and their importance to avoid race around conditions. But in the real world, only mutual exclusion is not enough. We may sometimes desire a thread to execute only if some condition is satisfied or else it should block.

One might argue that we can use a busy while loop which continuously checks for the required condition. Even I was also implementing using this strategy. But speaking truly, this makes the program quite inefficient due to the unwanted while loop computations.

Condition variables comes to rescue us from this issue. I give you a detailed view about this.

Condition Variables:

These are just like mutexes, not in their semantics, but the syntax which we use to declare it.

pthread_cond_t:

This is the type name used to declare the condition variables.


pthread_cond_init:

This function is used to initialize the condition variables. As I said before, this is much like the mutex declaration. The function prototype is as follows:

int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);

The first argument is a pointer to a condition variable and the second one is the condition attributes, which for now you can keep it as NULL, which makes it to take the default attributes.


pthread_cond_wait:

Now, here comes the vital function of the condition variables. The prototype is as follows:

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)

It takes two arguments, the first one is the condition variable and the second is the mutex which the calling thread has locked previously.It also releases the lock on the mutex by the calling thread. All these operations are performed at once. This function blocks the thread until pthread_signal function is called.


pthread_cond_signal:

The prototype is as follows:

int pthread_cond_signal(pthread_cond_t *cond)

It takes the condition variable as the agrument, and when this function is called the thread which was blocked with the call pthread_cond_wait will now be awaken.

There are two conditions for a thread to call this function:
1) The calling thread must have the lock on the mutex that was previously released by the thread which was blocked due to pthread_cond_wait.
2) The mutex that is with the calling thread must be released in the future, so that the blocked thread could get back the mutex and resume its execution.


There may be a little bit of confusion with those conditions, but that will be clear if we see an example program.

In this program, two threads initially keep on incrementing the count once in a second.
When the count reaches 20, the first thread gets blocked, because condition wait was called here. Then from here on, the second thread alone increments the count value upto 30.
Then the blocked thread resumes again and both count upto 40. Here, I was comparing two consecutive values because for a single value, there is a possibility of the value getting skipped.


#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#define T 20
int count=0;

pthread_mutex_t J;
pthread_cond_t con;
void fun1()
{
while(1)
{

   pthread_mutex_lock(&J);
   count++;
   if(count==T || count-1==T)
    {
      printf("waiting for t2\n");
    pthread_cond_wait(&con, &J);

    }
    if(count==40 || count==41)
    {
      pthread_mutex_unlock(&J);
      return;
    }
    printf("fun1(): count=%d\n", count);
   pthread_mutex_unlock(&J);
   sleep(1);
}
}
void fun2()
{
while(1)
{
   pthread_mutex_lock(&J);
   count++;
   if(count==40 || count==41)
    {
      pthread_mutex_unlock(&J);
      return;
    }
   if(count==30)
    pthread_cond_signal(&con);
  printf("fun2(): count=%d\n", count);
   pthread_mutex_unlock(&J);
   sleep(1);
}
}
void main(int argc, char* argv[])
{
    pthread_t A,B;
    pthread_cond_init(&con, NULL);
    pthread_mutex_init(&J, NULL);
    pthread_create(&A, NULL, (void*)&fun1, NULL);
    pthread_create(&B, NULL, (void*)&fun2, NULL);
    pthread_join(A, NULL);
exit(0);
}

Try to copy the code and execute it. You will clearly understand what is going on.


pthread_cond_broadcast:

In addition to the above functions, this function is used when more than one thread is waiting on same condition variable. This function call results in waking up of all those blocked threads. Its prototype is as shown:

int pthread_cond_broadcast(pthread_cond_t *cond)

pthread_exit:

Sometimes, you may want to terminate thread when it is in the middle of execution. You may say that i will just call return. Well, you are half correct then! Because, this idea won't work if a function calls another function and its the worst idea for recursive case!! So, the pthread library provides pthread_exit function, which immediately terminates the thread, even it is the 100th or 1000th function call. Its prototype is as follows:

void pthread_exit(void *value_ptr)

The only argument is the status of exit of the calling thread which is immaterial for now.


pthread_self:

At times you may want to know the process ID(as said before linux kernel doesn't differentiate between threads and processes, hence process ID!!) of the thread, you can use this function.

pthread_t pthread_self(void)

It returns the thread ID ( or process ID) of the calling thread


pthread_kill:

Like the kill command, in pthreads we have the method pthread_kill function which has nearly the same functionality. The prototype is as follows:

int pthread_kill(pthread_t thread, int sig)

It takes the pthread_t and an integer which indicates the signal. The different signal numbers can be viewed here.


These are the basic functions required to create and run pthreads conveniently. Although, still there are many functions in the library, I will leave it to the reader to explore them

<<Prev Next>>

2 comments:

  1. Is there any condition that the condition statement (pthread_cond_wait(&cond,&J)) should work.
    I once got the output as follows

    fun2(): count=1
    fun1(): count=2
    fun2(): count=3
    fun1(): count=4
    fun2(): count=5
    fun1(): count=6
    fun2(): count=7
    fun1(): count=8
    fun2(): count=9
    fun1(): count=10
    fun1(): count=11
    fun2(): count=12
    fun2(): count=13
    fun1(): count=14
    fun1(): count=15
    fun2(): count=16
    fun2(): count=17
    fun1(): count=18
    fun1(): count=19
    fun2(): count=20
    fun2(): count=21
    fun1(): count=22
    fun1(): count=23
    fun2(): count=24
    fun2(): count=25
    fun1(): count=26
    fun1(): count=27
    fun2(): count=28
    fun2(): count=29
    fun1(): count=30
    fun1(): count=31
    fun2(): count=32
    fun2(): count=33
    fun1(): count=34
    fun1(): count=35
    fun2(): count=36
    fun2(): count=37
    fun1(): count=38
    fun1(): count=39

    Is there anyway to get to this condition statement for sure

    ReplyDelete
    Replies
    1. The condition statement will always work. The problem here was the scheduling sequence of the threads. Although, this should never occur, it may be possibly due to some bug in my code, which I am going to look at.

      Delete