- 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