linux 线程同步机制和java的是极其类似的。如果不太明白java多线程编程,可以参考我原先写的java多线程编程。下面我们将展现linux下如何实现生产者和消费者模型。
直接上代码吧:
#ifndef _LIST_H_
#define _LIST_H_ #include <string.h> #include <stdio.h> struct List { char buffer[10]; char * cursor; char * begin; char * end; }; // you must add struct, otherwise it will prompt "expected ‘)’ before ‘*’ token" void init(struct List * p_list); int get_buffer_length (struct List * p_list); void put_into_buffer(struct List* p_list,char *pc_char); char get_from_buffer(struct List* p_list); #endif
这个头文件主要实现了一个数据结构,List,先进先出。
#include "list.h" void init(struct List * p_list){ memset(p_list->buffer,'\0',10); p_list->cursor=(p_list->buffer)+10; p_list->begin=p_list->buffer; p_list->end=(p_list->buffer)+10; } int get_buffer_length(struct List * p_list){ return p_list->end-p_list->cursor; } void put_into_buffer(struct List * p_list,char * pc_char){ printf("put ........ %c\n",*pc_char); if(p_list->cursor<=p_list->begin||p_list->cursor>p_list->end) printf(" put error"); //put the char into cursor's former place (p_list->cursor)--; memset(p_list->cursor,(int)(*pc_char),1); } char get_from_buffer(struct List * p_list){ if(p_list->cursor<p_list->begin||p_list->cursor>p_list->end) printf(" get error"); //put the char into cursor's former place char result=*(p_list->cursor); (p_list->cursor)++; printf("get ......... %c\n",result); return result; }
List的具体实现。
#include <pthread.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include "List.h" pthread_cond_t has_product = PTHREAD_COND_INITIALIZER; pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; //define the Producer thread void * produce(void * arg) { //arg is a char * pointer struct List * p_list=(struct List *)arg; //if buffer length =10,than wait,because buffer is full, while(1) { pthread_mutex_lock(&lock); //正确位置, printf("111111\n"); if(get_buffer_length(p_list)==10) { printf("22222222\n"); int num1=pthread_cond_wait(&has_product, &lock); printf("33333333\n"); printf(" num11111 %d\n",num1); } //buffer'length !=10,not full, we can put char into buffer. printf("444444\n"); //pthread_mutex_lock(&lock); //错误位置 printf("555555\n"); char zifu=(char)(1+(int)(128.0*rand()/(RAND_MAX+1.0))); put_into_buffer(p_list,&zifu); //after put, if the length>0,we can notify the wait thread,means that you can get char now if(get_buffer_length(p_list)==1) { pthread_cond_signal(&has_product); printf("66666\n"); } printf("777777777777\n"); int num3=pthread_mutex_unlock(&lock); printf("unlocknumber 1111111111111 is %d\n",num3); printf("888888888888\n"); sleep(1); printf("99999999\n"); } } //define the second thread void * comsume(void * arg) { //arg is a char * pointer struct List * p_list=(struct List *)arg; while(1) { //if buffer length =10,than wait,because buffer is full, pthread_mutex_lock(&lock); //正确位置, printf("aaaaaaaaaa\n"); if(get_buffer_length(p_list)==0) { printf("bbbbbbbbbbbbbb\n"); int num2=pthread_cond_wait(&has_product, &lock); printf("cccccccccccc\n"); printf(" num2222 %d\n",num2); } //buffer'length !=0,not full, we can get char into buffer. printf("dddddddddddddddd\n"); //int num4=pthread_mutex_lock(&lock); //错误位置 //printf("unlocknumber 222222222 is %d\n",num4); printf("eeeeeeeeeeeeee\n"); char zifu=get_from_buffer(p_list); //after get, if the length<10,we can notify the put thread,means that you can put now! if(get_buffer_length(p_list)<10) { pthread_cond_signal(&has_product); } printf("ffffffffffff\n"); pthread_mutex_unlock(&lock); printf("gggggggggggg\n"); sleep(2); printf("hhhhhhhhhhhhhh\n"); } } int main (int argc, char ** argv) { pthread_t tidA, tidB; struct List common; init(&common); pthread_create(&tidB, NULL, &comsume, &common); sleep(3); pthread_create(&tidA, NULL, &produce, &common); sleep(120); return 0; }
这个是具体的模型实现,特别注意的是produce和consume方法里面,我注释了,加锁的正确位置和错误位置。如果加锁的位置在错误位置会引起死锁,具体方法,还是用“颜色”分析方法。
首先cosumer进行wait,使其在mutex上进入等待队列,线程切换到produce线程上面执行,然后produce释放锁,consumer居然又要lock mutex,所以互斥,consumer线程就死了,然后produce循环过来,也要lock mutex,所以produce线程也死了。就这样,正确lock mutex位置在文中进行了标注。