Condition variables --- producers and consumers

  • Suppose there is a producer thread, a thread consumer, a production and consumption a. Let's look at how to achieve.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int buffer;
int count = 0;

void put(int value)
{
        assert(count == 0);
        count = 1;
        buffer = value;
}

int get()
{
        assert(count == 1);
        count = 0;
        return buffer;
}

void *producer(void *arg)
{
        printf("producer...\n");
        int i;
        int loops = (int) arg;
        for (i = 0; i < loops; i++) {
                put(i);
                printf("put:%d\n",i);
        }
}

void *consumer(void *arg)
{
        printf("consumer...\n");
        int i;
        while(1) {
                int tmp = get();
                printf("%d\n",tmp);
        }
}

int main ()
{
        printf("begin...\n");
        pthread_t p;
        pthread_create(&p, NULL, consumer,(void *)100);
        producer((void*)100);
        pthread_join(p, NULL);
        return 0;
}

The above code is run, obviously does not meet our requirements, this time need to condition variable.

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

int buffer;
int count = 0;

pthread_cond_t cond;
pthread_mutex_t mutex;

void put(int value) 
{
    assert(count == 0);
    count = 1;
    buffer = value;
}

int get()
{
    assert(count == 1);
    count = 0;
    return buffer;
}

void *producer(void *arg)
{
    printf("producer...\n");
    int i;
    int loops = (int) arg;
    for (i = 0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        if(count == 1)
            pthread_cond_wait(&cond, &mutex);
        put(i);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
        printf("put:%d\n",i);
    }
}

void *consumer(void *arg)
{
    printf("consumer...\n");
    int i;
    int loops = (int)arg;
    for(i =0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        if(count == 0)
            pthread_cond_wait(&cond, &mutex);
        int tmp = get();
        printf("%d\n",tmp);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
}
[zf@localhost ch30]$ ./a.out 
begin...
producer...
put:0
consumer...
0
put:1
1
put:2
2
put:3
3
put:4
4

Results, to be adequate, but if there are two consumers?

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

int buffer;
int count = 0;

pthread_cond_t cond;
pthread_mutex_t mutex;

void put(int value) 
{
    assert(count == 0);
    count = 1;
    buffer = value;
}

int get()
{
    assert(count == 1);
    count = 0;
    return buffer;
}

void *producer(void *arg)
{
    printf("producer...\n");
    int i;
    int loops = (int) arg;
    for (i = 0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        if(count == 1)
            pthread_cond_wait(&cond, &mutex);
        put(i);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
        printf("put: %d",i);
    }
}

void *consumer(void *arg)
{
    printf("consumer...\n");
    int i;
    int loops = (int)arg;
    for(i =0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        if(count == 0)
            pthread_cond_wait(&cond, &mutex);
        int tmp = get();
        printf("[%d]get: %d\n",pthread_self(),tmp);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
}

int main ()
{
    printf("begin...\n");
     pthread_t p,p1;
    pthread_create(&p, NULL, consumer,(void *)10000);
    pthread_create(&p1, NULL, consumer, (void*)10000);

    producer((void*)20000);
    pthread_join(p, NULL);
    pthread_join(p1, NULL);
    return 0;
}
put: 1207[1848375040]get: 1207
put: 1208[1839982336]get: 1208
put: 1209[1848375040]get: 1209
put: 1210[1839982336]get: 1210
put: 1211[1848375040]get: 1211
a.out: main.c:21: get: Assertion `count == 1' failed.
Abandoned (spit nuclear)

We found a failure, and this is why? Let's think about, first sentence, and if a relationship. That is, consumers Tc1 is the wake-up time, just be preempted Tc2, the consumption of the cache, resulting in longer time Tc1 consumption triggers assert that this question should be how to do it? In fact, very simple to use while in place if, we once again check the capacity.

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

int buffer;
int count = 0;

pthread_cond_t cond;
pthread_mutex_t mutex;

void put(int value) 
{
    assert(count == 0);
    count = 1;
    buffer = value;
}

int get()
{
    assert(count == 1);
    count = 0;
    return buffer;
}

void *producer(void *arg)
{
    printf("producer...\n");
    int i;
    int loops = (int) arg;
    for (i = 0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        while(count == 1)
            pthread_cond_wait(&cond, &mutex);
        put(i);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
        printf("put: %d",i);
    }
}

void *consumer(void *arg)
{
    printf("consumer...\n");
    int i;
    int loops = (int)arg;
    for(i =0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        while(count == 0)
            pthread_cond_wait(&cond, &mutex);
        int tmp = get();
        printf("[%d]get: %d\n",pthread_self(),tmp);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
}

int main ()
{
    printf("begin...\n");
     pthread_t p,p1;
    pthread_create(&p, NULL, consumer,(void *)10000);
    pthread_create(&p1, NULL, consumer, (void*)10000);

    producer((void*)20000);
    pthread_join(p, NULL);
    pthread_join(p1, NULL);
    return 0;
}
put: 1276[1475249920]get: 1276
put: 1277[1466857216]get: 1277
put: 1278[1475249920]get: 1278
put: 1279[1466857216]get: 1279
put: 1280[1475249920]get: 1280
put: 1281[1466857216]get: 1281
put: 1282[1466857216]get: 1282
put: 1283[1475249920]get: 1283
put: 1284[1466857216]get: 1284
put: 1285[1466857216]get: 1285

But the results are not as expected, found that half of the program execution to not move, stuck. Why is this? We look at the plus print

void *producer(void *arg)
{
    printf("producer...\n");
    int i;
    int loops = (int) arg;
    for (i = 0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        while(count == 1){
            printf("producer wait......\n");
            pthread_cond_wait(&cond, &mutex);
        }
        put(i);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
        printf("put: %d",i);
    }
}

void *consumer(void *arg)
{
    printf("consumer...\n");
    int i;
    int loops = (int)arg;
    for(i =0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        while(count == 0){
            printf("consumer wait.....\n");
            pthread_cond_wait(&cond, &mutex);
        }
        int tmp = get();
        printf("[%d]get: %d\n",pthread_self(),tmp);
        pthread_cond_signal(&cond);
        pthread_mutex_unlock(&mutex);
    }
}
put: 197producer wait......
[632694528]get: 197
consumer wait.....
consumer wait.....

This finding is a problem, that is, after T1 consumer spending, wake up is T2, so that three threads are dormant, this is a terrible problem, how should we do it? Logically, after consumer spending should wake producers, so consumers and producers should send a different signal, this is not enough yet

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

int buffer;
int count = 0;

pthread_cond_t empty,fill;
pthread_mutex_t mutex;

void put(int value) 
{
    assert(count == 0);
    count = 1;
    buffer = value;
}

int get()
{
    assert(count == 1);
    count = 0;
    return buffer;
}

void *producer(void *arg)
{
    printf("producer...\n");
    int i;
    int loops = (int) arg;
    for (i = 0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        while(count == 1){
            printf("producer wait......\n");
            pthread_cond_wait(&empty, &mutex);
        }
        put(i);
        pthread_cond_signal(&fill);
        pthread_mutex_unlock(&mutex);
        printf("put: %d",i);
    }
}

void *consumer(void *arg)
{
    printf("consumer...\n");
    int i;
    int loops = (int)arg;
    for(i =0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        while(count == 0){
            printf("consumer wait.....\n");
            pthread_cond_wait(&fill, &mutex);
        }
        int tmp = get();
        printf("[%d]get: %d\n",pthread_self(),tmp);
        pthread_cond_signal(&empty);
        pthread_mutex_unlock(&mutex);
    }
}

int main ()
{
    printf("begin...\n");
     pthread_t p,p1;
    pthread_create(&p, NULL, consumer,(void *)10000);
    pthread_create(&p1, NULL, consumer, (void*)10000);

    producer((void*)20000);
    pthread_join(p, NULL);
    pthread_join(p1, NULL);
    return 0;
}
put: 19997producer wait......
[754308864]get: 19997
consumer wait.....
put: 19998producer wait......
[754308864]get: 19998
consumer wait.....
put: 19999[754308864]get: 19999

Here, two problems are solved, it is not very happy. Not happy too early, although this program is available, but not very common, we can not just a buffer, let's change to change again

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

#define MAX 1000

int buffer[MAX];
int fills = 0;
int use   = 0;
int count = 0;

pthread_cond_t empty,fill;
pthread_mutex_t mutex;

void put(int value) 
{
    buffer[fills] = value;
    fills = (fills + 1) % MAX;
    count++;
}

int get()
{
    int tmp = buffer[use];
    use = (use + 1) % MAX;
    count--;
    return tmp;
}

void *producer(void *arg)
{
    printf("producer...\n");
    int i;
    int loops = (int) arg;
    for (i = 0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        while(count == MAX){
            printf("producer wait......\n");
            pthread_cond_wait(&empty, &mutex);
        }
        put(i);
        pthread_cond_signal(&fill);
        pthread_mutex_unlock(&mutex);
        printf("put: %d",i);
    }
}

void *consumer(void *arg)
{
    printf("consumer...\n");
    int i;
    int loops = (int)arg;
    for(i =0; i < loops; i++) {
        pthread_mutex_lock(&mutex);
        while(count == 0){
            printf("consumer wait.....\n");
            pthread_cond_wait(&fill, &mutex);
        }
        int tmp = get();
        printf("[%d]get: %d\n",pthread_self(),tmp);
        pthread_cond_signal(&empty);
        pthread_mutex_unlock(&mutex);
    }
}

int main ()
{
    printf("begin...\n");
     pthread_t p,p1;
    pthread_create(&p, NULL, consumer,(void *)10000);
    pthread_create(&p1, NULL, consumer, (void*)10000);

    producer((void*)20000);
    pthread_join(p, NULL);
    pthread_join(p1, NULL);
    return 0;
}
[-797354240]get: 19988
[-797354240]get: 19989
[-797354240]get: 19990
[-797354240]get: 19991
[-797354240]get: 19992
[-797354240]get: 19993
[-797354240]get: 19994
[-797354240]get: 19995
consumer wait.....
put: 19996put: 19997put: 19998put: 19999[-797354240]get: 19996
[-797354240]get: 19997
[-797354240]get: 19998
[-797354240]get: 19999

This almost ha, really fast too! ! ! Hehe

reference:

  • Introduction to Operating Systems

Guess you like

Origin www.cnblogs.com/vczf/p/11886512.html