1

Two threads in the program alternately print even and odd numbers till 100. I have tried this and it worked. Is there a way to access the value of the shared data inside main and terminate the 2 threads when the value reaches 100

#include<stdio.h>
#include<pthread.h>

pthread_t tid[2];
unsigned int shared_data = 0;
pthread_mutex_t mutex;
unsigned int rc;
//prototypes for callback functions

void* PrintEvenNos(void*);
void* PrintOddNos(void*);

void main(void)
{
    pthread_create(&tid[0],0,&PrintEvenNos,0)
    pthread_create(&tid[1],0,&PrintOddNos,0);
    sleep(3);

    pthread_join(tid[0],NULL);
    pthread_join(tid[1],NULL);
}

void* PrintEvenNos(void *ptr)
{
    pthread_mutex_lock(&mutex);
    do
    {
       if(shared_data%2 == 0)
       {
         printf("Even:%d\n",shared_data);
         shared_data++;
       } else {
          rc=pthread_mutex_unlock(&mutex);//if number is odd, do not print, release mutex
       }
    } while(shared_data <= 100);
}

void* PrintOddNos(void* ptr1)
{
    rc = pthread_mutex_lock(&mutex);
    do
    {
       if(shared_data%2 != 0)
       {
          printf("odd:%d\n",shared_data);
          shared_data++;
       } else {
          rc = pthread_mutex_unlock(&mutex);//if number is even, do not print, release mutex
       }
    } while(shared_data <= 100);
}
Karthick
  • 1,010
  • 1
  • 8
  • 24
Nanobrains
  • 275
  • 1
  • 3
  • 11
  • Well, does it? Have you tried it? – Carey Gregory Feb 25 '14 at 04:43
  • This program will print zero or two numbers depending on which thread executes first and then stop, as the threads do not perform a kind of internal looping. If `PrintEvenNos` runs first, it prints 0, updates shared_data to 1 and terminates; then `PrintOddNos` runs, prints 1, updates shared_data to 2 and terminates. If `PrintOddNos` runs first, it print nothings (shared_data is 0, i.e. even), updates shared_data to 1 and terminates; then `PrintEvenNos` runs, print nothings (shared_data is 1, i.e. odd), updates shared_data to 2 and terminates. – isedev Feb 25 '14 at 04:46
  • I dint try it yet! I will try it soon. I am just trying to understand how mutex actually works. – Nanobrains Feb 28 '14 at 08:54
  • I tried after editing the program and it works fine now! – Nanobrains Mar 07 '14 at 18:34
  • It works fine. But there is problem is that you are unlocking mutex each time without locking. Your pthread_mutex_lock(&mutex); statement should be into loop. – Pankaj Vavadiya Mar 28 '21 at 13:59

7 Answers7

6
Use condition variable to synchronize both threads and a mutex to protect count

#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"

pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition_var = PTHREAD_COND_INITIALIZER;
void *functionCount1();
void *functionCount2();
int count = 0;
#define COUNT_DONE 200

void main()
{
 pthread_t thread1, thread2;
 pthread_create( &thread1, NULL, &functionCount1, NULL);
 pthread_create( &thread2, NULL, &functionCount2, NULL);
 pthread_join( thread1, NULL);
 pthread_join( thread2, NULL);
 exit(0);
}

// Print odd numbers
void *functionCount1()
{
  for(;;) {
   // Lock mutex and then wait for signal to relase mutex
   pthread_mutex_lock( &count_mutex );
   if ( count % 2 != 0 ) {
     pthread_cond_wait( &condition_var, &count_mutex );
   }
   count++;
   printf("Counter value functionCount1: %d\n",count);
   pthread_cond_signal( &condition_var );
   if ( count >= COUNT_DONE ) {
     pthread_mutex_unlock( &count_mutex );
     return(NULL);
   }
   pthread_mutex_unlock( &count_mutex );
 }
}

// print even numbers
void *functionCount2()
{
  for(;;) {
  // Lock mutex and then wait for signal to relase mutex
  pthread_mutex_lock( &count_mutex );
  if ( count % 2 == 0 ) {
    pthread_cond_wait( &condition_var, &count_mutex );
  }
  count++;
  printf("Counter value functionCount2: %d\n",count);
  pthread_cond_signal( &condition_var );
  if( count >= COUNT_DONE ) {
    pthread_mutex_unlock( &count_mutex );
    return(NULL);
  }
  pthread_mutex_unlock( &count_mutex );
 }
}
amdube
  • 73
  • 1
  • 6
4

There were few errors, in the code I posted earlier, I corrected those mistakes and this program prints even and odd values from 0 to 100, I have tried it.

#include<stdio.h>
#include<pthread.h>

pthread_t tid[2];
unsigned int shared_data = 0;
pthread_mutex_t mutex;
unsigned int rc;
//prototypes for callback functions

void* PrintEvenNos(void*);
void* PrintOddNos(void*);

void main(void)
{
    pthread_create(&tid[0],0,&PrintEvenNos,0);
    pthread_create(&tid[1],0,&PrintOddNos,0);
    sleep(3);

    pthread_join(tid[0],NULL);
    pthread_join(tid[1],NULL);
}

void* PrintEvenNos(void *ptr)
{
     rc = pthread_mutex_lock(&mutex);
     do
     {
         if(shared_data%2 == 0)
         {
             printf("Even:%d\n",shared_data);
             shared_data++;
         }
         else
         {
             rc=pthread_mutex_unlock(&mutex);//if number is odd, do not print, release mutex
         }
     } while (shared_data <= 100);
}

void* PrintOddNos(void* ptr1)
{
    rc = pthread_mutex_lock(&mutex);
    do
    {
        if(shared_data%2 != 0)
        {
            printf("odd:%d\n",shared_data);
            shared_data++;
        }
        else
        {
            rc = pthread_mutex_unlock(&mutex);//if number is even, do not print, release mutex
        }
    } while (shared_data <= 100);
}
eeerahul
  • 1,629
  • 4
  • 27
  • 38
Nanobrains
  • 275
  • 1
  • 3
  • 11
  • 1
    i think use of signal variable in necessary , from scheduler point of view , scheduler try to give 50-50 % weight to parallel running thread , but there is no guarantee , what if thread 2nd start little bit late because of scheduler , this program may miss some count , although its a hypothetical scenario , not sure about it. – pankaj kushwaha Dec 18 '17 at 14:11
  • 1
    @Nanobrains: Nothing looks improved. It works fine. But there is problem is that you are unlocking mutex each time without locking. Your pthread_mutex_lock(&mutex); statement should be into loop. – Pankaj Vavadiya Mar 28 '21 at 14:16
  • position of mutex lock needs to be inside loop. – Jeegar Patel Jul 09 '21 at 19:13
4
#include<stdio.h>
#include<pthread.h>
int data =0;

pthread_mutex_t lock;
pthread_cond_t cond;

void * even(void *tid)
{
    while(data < 30)
    {
        pthread_mutex_lock(&lock);
        if(data%2)
            pthread_cond_wait(&cond,&lock);
        else
        {
            printf("Tid %ld even %d\n",pthread_self(),data++);
            pthread_cond_signal(&cond);
        }
            pthread_mutex_unlock(&lock);    // should come outside else as mutex is locked above if
    }
    pthread_exit(&data);
}

void * odd()
{
    while(data < 30) 
    {   
        pthread_mutex_lock(&lock);
        if(!(data%2))
            pthread_cond_wait(&cond,&lock);
        else
        {
            printf("Tid %ld odd %d\n",pthread_self(),data++);
            pthread_cond_signal(&cond);
        }
            pthread_mutex_unlock(&lock);
    }   
    pthread_exit(&data);
}

int main()
{
    pthread_mutex_init(&lock,NULL);
    pthread_cond_init(&cond,NULL);
    pthread_t tid[2];
    pthread_create(&tid[0],NULL,even, (void*)&tid[0]);
    pthread_create(&tid[1],NULL,odd, (void*)&tid[1]);
    void *ret[2];
    pthread_join(tid[0], &ret[0]);
    pthread_join(tid[1], &ret[1]);
    printf("return value %d \n",*(int*)ret[0]);
    printf("return value %d \n",*(int*)ret[1]);

    return 0;
}
Khrusos
  • 51
  • 5
2
Prints: 
Counter value functionCount2: 0
Counter value functionCount1: 1
Counter value functionCount2: 2
Counter value functionCount1: 3
Counter value functionCount2: 4
Counter value functionCount1: 5
Counter value functionCount2: 6
Counter value functionCount1: 7
Counter value functionCount2: 8
Counter value functionCount1: 9

#include "stdio.h"
#include "stdlib.h"
#include "pthread.h"

pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t condition_var = PTHREAD_COND_INITIALIZER;
void *functionCount1();
void *functionCount2();
int count = 0;
#define COUNT_DONE 10

void main()
{
    pthread_t thread1, thread2;
    pthread_create( &thread1, NULL, &functionCount1, NULL);
    pthread_create( &thread2, NULL, &functionCount2, NULL);
    pthread_join( thread1, NULL);
    pthread_join( thread2, NULL);
    exit(0);
}

// Print odd numbers
void *functionCount1()
{
    for(;;) {
        // Lock mutex and then wait for signal to relase mutex
        pthread_mutex_lock( &count_mutex );
        if ( count % 2 != 0 ) {
            printf("Counter value functionCount1: %d\n",count);
            count++;
            pthread_cond_signal( &condition_var );
        } else {
            pthread_cond_wait( &condition_var, &count_mutex );
        }
        if ( count >= COUNT_DONE ) {
            pthread_mutex_unlock( &count_mutex );
            return(NULL);
        }
        pthread_mutex_unlock( &count_mutex );
    }
}

// print even numbers
void *functionCount2()
{
    for(;;) {
        // Lock mutex and then wait for signal to relase mutex
        pthread_mutex_lock( &count_mutex );
        if ( count % 2 == 0 ) {
            printf("Counter value functionCount2: %d\n",count);
            count++;
            pthread_cond_signal( &condition_var );
        } else {
            pthread_cond_wait( &condition_var, &count_mutex );
        }
        if( count >= COUNT_DONE ) {
            pthread_mutex_unlock( &count_mutex );
            return(NULL);
        }
        pthread_mutex_unlock( &count_mutex );
    }
}
Haswell
  • 1,573
  • 1
  • 18
  • 45
  • This looks perfect and also working fine. – Pankaj Vavadiya Mar 28 '21 at 14:02
  • This seems correct solution. With ptheard_cond_signal/wait only you can avoid re-acquiring mutex by same thread again and again. https://stackoverflow.com/questions/37860811/do-mutexes-guarantee-ordering-of-acquisition – Jeegar Patel Jul 09 '21 at 19:22
0

This is a spectacularly bad use case for threading. Having two threads simply alternating workload will not gain you anything. The general idea is to allow threads to do other work while waiting for some resource to become available.

In the case where your two threads are either doing useful work or doing absolutely nothing while waiting for useful work to become available, you're better off doing it in a single thread of execution.

Having said that, you can divide the workload up into threads but the way you've done it is problematic. First, each of your threads simply processes one number then exits, so you won't be getting anywhere near a hundred numbers printed out.

Second, even if they did loop, each line like:

if(shared_data++ %2 == 0)

will increment the shared data even when it's not supposed to. That's going to lead to "interesting" results in the output. Think of the case where each thread goes through many iterations of its loop before switching to the other thread.

Because it's incrementing regardless of the current value, you're likely to see something like:

0 2 4 6 7 9 11 13 14 16 18 20 21 23 ...

The pseudo-code for threads that will work requires that each thread do nothing to affect the data until it's their turn. First, the main thread, not much different from yours:

def main()
    set item to 0
    start thread evenThread
    start thread oddThread
    wait for evenThread to finish
    wait for oddThread to finish
    exit

Then the two worker threads, very similar in structure:

def evenThread():
    grab mutex
    repeat forever:
        while item is odd:
            release mutex
            yield if possible
            grab mutex

        # item now guaranteed to be even
        print item
        increment item
        if item is 101:
            exit repeat loop
    release mutex

def oddThread():
    grab mutex
    repeat forever:
        while item is even:
            release mutex
            yield if possible
            grab mutex

        # item now guaranteed to be odd
        print item
        increment item
        if item is 100:
            exit repeat loop
    release mutex

However, even if you want this done in a threaded manner, mutexes aren't necessarily a good way to do it. There's a chance that each thread will continue to run after it's done its work for this cycle, resulting in wasted work (the yield in the above pseudo-code is an effort to alleviate this, however I'm pretty certain yield is not mandated by pthreads - it may be a non-portable extension however).

There are far better (ie, deterministic) ways to effect communications between threads that know control has to be transferred. Things such as condition variables, for example.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • In question, It mentioned the solution required for C language. Then there is no meaning to share code in another language and wasting of people's time. – Pankaj Vavadiya Mar 28 '21 at 13:20
  • @Pankaj, I beg to differ. The intent is to show the algorithm to use, not a specific implementation. There'slittle to be gained by turning it into C since, as I've already stated, it's a bad use case, included only for completeness. – paxdiablo Mar 29 '21 at 02:25
0
mutex m;
condition_variable cv;
int num = 0;

void Even()
{
    while (true)
    {
        {
            unique_lock<mutex> ul(m);
            cv.wait(ul, [&]() {return num % 2 == 0; });
            cout <<"Even "<<num << endl;
            num++;
            cv.notify_one();
        }
    }
}

void Odd()
{
    while (true)
    {
        {
            unique_lock<mutex> ul(m);
            cv.wait(ul, [&]() {return num % 2 == 1; });
            cout <<"ODD "<< num << endl;
            num++;
            cv.notify_one();
        }
    }
}

int main()
{
    thread t1(Odd);
    
    thread t2(Even);

    t1.join();
    t2.join();

    return 0;
}
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 12 '21 at 14:13
-1

The below is the c code to print even and odd number using the two threads, with send signal to other thread once the first thread done , so that second thread backup and start using the resource. below program is working fine !!!

output:
odd_thread: 1
Even_Thread: 2
odd_thread: 3
Even_Thread: 4
odd_thread: 5
Even_Thread: 6
odd_thread: 7
Even_Thread: 8
odd_thread: 9
Even_Thread: 10


#include <stdio.h>
#include <pthread.h>


int n = 1;
int max = 10;


pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  even = PTHREAD_COND_INITIALIZER;
pthread_cond_t  odd =  PTHREAD_COND_INITIALIZER;

void* print_odd(void *x)
{
  do
  {
    pthread_mutex_lock(&lock);
    if(n%2 != 1 )
    {
        pthread_cond_wait(&odd, &lock);
        pthread_mutex_unlock(&lock);
        pthread_cond_signal(&even);

    }
    else{
    printf("odd Thread: %d\n", n);
    n++;
    pthread_mutex_unlock(&lock);
    pthread_cond_signal(&even);
    }
    }while(n <= max);

    pthread_exit(NULL);

    }


  void* print_even(void *x)
  {
    do
    {
    pthread_mutex_lock(&lock);
    if(n%2 != 0)
    {
        pthread_cond_wait(&even, &lock);
        pthread_mutex_unlock(&lock);
        pthread_cond_signal(&odd);

    }
    else{
    printf("Even Thread: %d\n", n);
    n++;
    pthread_mutex_unlock(&lock);
    pthread_cond_signal(&odd);
    }
    }while(n <= max);

     pthread_exit(NULL);

     }

     int main()
     {
      pthread_t t1, t2;

      pthread_create(&t1, NULL, print_odd, NULL);
      pthread_create(&t2, NULL, print_even, NULL);

      pthread_join(t1, NULL);
      pthread_join(t2, NULL);

     return 0;

    }
  • 2
    Welcome to Stack Overflow. Code is a lot more helpful when it is accompanied by an explanation. Stack Overflow is about learning, not providing snippets to blindly copy and paste. This is particularly important when answering old questions with existing answers. Please [edit] your question and explain how it answers the specific question being asked, and how it is better than what's already here. See [answer]. – ChrisGPT was on strike Nov 11 '21 at 13:45