0

suppose i have three threads th1, th2, and th3 in a process and three registers (arrays) a, b, and c. th1 and th2 only writes to one of the three registers and th3 will only read data from these registers. th1, th2 and th3 will work in consecutive order b/c of waiting on condition variables. two condition variables cv1 and cv2 are used for signalling between (th1,th2) and (th2,th3) respectively. working procedures is as follows:

  1. first th1 writes some thing into 'a' array, then signal (using cv1) th2 which was waiting for it.
  2. after receiving signal from th1, th2 starts writing to the same array, 'a', then signal (using cv2) th3 for reading 'a'.
  3. th3 starts reading 'a' (same array) on receiving signal from th2.
  4. above 3 steps repeats for 'b' and 'c' in same manner.

my c code is below:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>

void* th1();
void* th2();
void* th3();

int a[40], b[40], c[40], rn;

pthread_mutex_t mutex1, mutex2, mutex3;
pthread_cond_t cv1, cv2;

int main()
{
    pthread_t  t[3];
    pthread_mutex_init(&mutex1, NULL);
    pthread_mutex_init(&mutex2, NULL);
    pthread_mutex_init(&mutex3, NULL);

    pthread_cond_init(&cv1, NULL);
    pthread_cond_init(&cv2, NULL);

    pthread_create(&t[0], NULL, th1, NULL);
    pthread_create(&t[1], NULL, th2, NULL);
    pthread_create(&t[2], NULL, th3, NULL);


    pthread_join(t[0], NULL);
    pthread_join(t[1], NULL);
    pthread_join(t[2], NULL);

    pthread_mutex_destroy(&mutex1);
    pthread_mutex_destroy(&mutex2);
    pthread_mutex_destroy(&mutex3);
    pthread_cond_destroy(&cv1);
    pthread_cond_destroy(&cv2);
    return 0;
}

void* th1()
{       
    pthread_mutex_lock(&mutex1);
        for(int i=0; i<20; i++)
        {
            a[i]=i;
            }
        pthread_cond_signal(&cv1);
        puts("a signal sent...");
    pthread_mutex_unlock(&mutex1);


    pthread_mutex_lock(&mutex2);
        for(int i=0; i<20; i++)
        {
            b[i]=i;
            }
        pthread_cond_signal(&cv1);
        puts("b signal sent...");
    pthread_mutex_unlock(&mutex2);


    pthread_mutex_lock(&mutex3);
        for(int i=0; i<20; i++)
        {
            c[i]=i;
            }
        pthread_cond_signal(&cv1);
        puts("c signal sent...");
    pthread_mutex_unlock(&mutex3);

    pthread_exit(NULL);
}

void* th2()
{
    pthread_mutex_lock(&mutex1);
        pthread_cond_wait(&cv1, &mutex1);
        puts("signal recv form th1 for writing 'a'...\n");
        for(int i=0; i<=20; i++)
        {
            a[i+20]=i+20;
        }
        pthread_cond_signal(&cv2);
    pthread_mutex_unlock(&mutex1);


    pthread_mutex_lock(&mutex2);
        pthread_cond_wait(&cv1, &mutex2);
        puts("signal recv from th1 for writing 'b'...\n");
        for(int i=0; i<=20; i++)
        {
            b[i+20]=i+20;
        }
        pthread_cond_signal(&cv2);
    pthread_mutex_unlock(&mutex2);


    pthread_mutex_lock(&mutex3);
        pthread_cond_wait(&cv1, &mutex3);
        puts("signal recv from th1 for writing 'c'...\n");
        for(int i=0; i<=20; i++)
        {
            c[i+20]=i+20;
        }
        pthread_cond_signal(&cv2);
    pthread_mutex_unlock(&mutex3);

    pthread_exit(NULL);
}
void* th3()
{

    pthread_mutex_lock(&mutex1);
        pthread_cond_wait(&cv2, &mutex1);
        puts(" signal recv from th2 for reading 'a'...\n");
        for(int i=0; i<=40; i++)
        {
            printf("%d   :",a[i]);
        }
        printf("\n\n");
    pthread_mutex_unlock(&mutex1);


    pthread_mutex_lock(&mutex2);
        pthread_cond_wait(&cv2, &mutex2);
        puts(" signal recv from th2 for reading 'b'...\n");
        for(int i=0; i<=40; i++)
        {
            printf("%d   :",b[i]);
        }
        printf("\n\n");
    pthread_mutex_unlock(&mutex2);


    pthread_mutex_lock(&mutex3);
        pthread_cond_wait(&cv2, &mutex3);
        puts(" signal recv from th2 for reading 'c'...\n");
        for(int i=0; i<=40; i++)
        {
            printf("%d   :",c[i]);
        }
        printf("\n\n");
    pthread_mutex_unlock(&mutex3);

    pthread_exit(NULL);

}

output blocks after showing just:

mohtashim-ul-haq@mohtashim-pc:~/Documents/rough$ gcc tread.c -o tread -lpthread
mohtashim-ul-haq@mohtashim-pc:~/Documents/rough$ ./tread
a signal sent...
b signal sent...
c signal sent...

where my expected output is something like:

    a signal sent
    signal recv form th1 for writing 'a'...
    signal recv from th2 for reading 'a'...
    1 2 3 4 ..... 40

    b signal sent
    signal recv form th1 for writing 'b'...
    signal recv from th2 for reading 'b'...
    1 2 3 4 ..... 40

    c signal sent
    signal recv form th1 for writing 'c'...
    signal recv from th2 for reading 'c'...
    1 2 3 4 ..... 40

i think, i could not understand how condition variable works in conjunction with mutexes. any help???

alk
  • 69,737
  • 10
  • 105
  • 255
User_890
  • 169
  • 1
  • 9

1 Answers1

0

You need to integrate the event "signal", will say you need to store if a signal (notifying about a state change) was raised.

For the 1st event ("a" read) adjustments to your code might look like this:

int a_read = 0; /* to store the event "a had been read" actually happened */

void* th1(void * pvunused)
{       
    pthread_mutex_lock(&mutex1);
    for(int i=0; i<20; i++)
    {
        a[i]=i;
    }

    a_read = 1;
    pthread_cond_signal(&cv1);
    ...


void* th2(void * pvunused)
{
  pthread_mutex_lock(&mutex1);
  while (0 == a_read) /* Theoretical an "if" would do here, 
                         using "while" lets you stay on the safe side, in case
                         a "spurious wake-up" (https://en.wikipedia.org/wiki/Spurious_wakeup)
                         occurred. */
  {
    pthread_cond_wait(&cv1, &mutex1);
  }

  ...
alk
  • 69,737
  • 10
  • 105
  • 255
  • perfect! it means blocking wait call will not automatically receive signal from other threads rather it requires a constant check on a some 'work_end_flag' from called thread... – User_890 Jun 27 '17 at 10:03
  • @mohtashim: "*blocking wait call will not automatically receive signal from other threads*" sure it will .. *if* this "other" thread is waiting already. If it's not waiting yet for condition to be signaled it would miss it, that why the fact it was signaled needs to be stored, which is done by the related condition-variable. – alk Jun 27 '17 at 14:57
  • suppose a case and let me know right concept if am misunderstanding: th1 runs first and the atomic code between mutex_lock and mutex_unlock set a_read == 1.after that th2 runs where while (0 == a_read) gets fails (b/c a_read == 1) so actually pthread_cond_wait(&cv1, &mutex1) in th2 will not receive any signal and other code outside while loop will execute only... – User_890 Jun 27 '17 at 16:28
  • case 2: if th2 runs first then it will wait for signal (b/c a_read==0) from th1. as th1 runs, it sets a_read == 1 and send signal, which will be received by th2. it means here there is no need of a_read flag i.e th2 already waiting for signal from th1??? – User_890 Jun 27 '17 at 16:34
  • @mohtashim: Case 1 and 2 both can occur with the code shown, so yes, the flag `a_read` is to cover case 1 ... *and* as well to cover the case of a thread waking up unexpected. Please read the link I put into my code's comment. – alk Jun 27 '17 at 19:10
  • @mohtashim please also see this answer: https://stackoverflow.com/a/20772586/694576 – alk Jun 27 '17 at 19:17