使用 线程 pthread_mutex 和 pthread_cond 实现一个生产者和多个消费者

一个简单的生产者消费者程序,大致思想如下:一个生产者线程,多个消费者线程,一个缓存区。缓冲区由整形数组实现,以数值-1表示清零,写入的数据为非负数。以一个结构体包含缓冲区和必要的线程锁与条件变量。以下分别有C++和C语言实现:

C++实现:

  1 1 #include <stdio.h>  
  2   2 #include <stdlib.h>
  3   3 #include <pthread.h>
  4   4 #include <unistd.h>
  5   5 #include <sys/select.h>
  6   6 #include <string.h>
  7   7 
  8   8 #define BUFF_SIZE 16    // 缓存区大小
  9   9 #define CONSUMER_NUM 3    // 消费者人数
 10  10 
 11  11 struct prodcons 
 12  12 {
 13  13     int buffer[BUFF_SIZE];
 14  14     pthread_mutex_t lock;
 15  15     int readpos,writepos;
 16  16     pthread_cond_t notEmpty;
 17  17     pthread_cond_t notFull;
 18  18 };
 19  19 
 20  20 typedef struct prodcons prodcons_t;
 21  21 
 22  22 class ProducterConsumer
 23  23 {
 24  24 public:
 25  25     ProducterConsumer();
 26  26     static void initial(prodcons_t* shareStruct);
 27  27     static void* producer(void* arg);            // 生产者线程执行函数
 28  28     static void* consumer(void* threadNum);    // 消费者线程执行函数
 29  29     static void stopThread();        // 销毁生产者消费者线程
 30  30 
 31  31 protected:    
 32  32     static void writeIn(prodcons_t *shareStruct,int data);
 33  33     static int readOut(prodcons_t *shareStruct, int threadNum);
 34  34     void createThread();    // 创建生产者和消费者
 35  35     
 36  36 private:
 37  37     static prodcons_t m_prodconsStruct;    // 共享结构体
 38  38     static bool m_isStop;        // 判断停止线程
 39  39     static pthread_t m_pidPro;    // 生产者线程id
 40  40     static pthread_t m_pidCon[CONSUMER_NUM];    // 消费者线程id
 41  41     
 42  42 };
 43  43 
 44  44 prodcons_t ProducterConsumer:: m_prodconsStruct;
 45  45 bool  ProducterConsumer::m_isStop = false;
 46  46 pthread_t ProducterConsumer::m_pidPro = 0;
 47  47 pthread_t ProducterConsumer::m_pidCon[CONSUMER_NUM] = {0};
 48  48 
 49  49 ProducterConsumer::ProducterConsumer()
 50  50 {
 51  51     initial(&m_prodconsStruct);
 52  52     createThread();
 53  53 }
 54  54 
 55  55 void ProducterConsumer::initial(prodcons_t *shareStruct)
 56  56 {
 57  57     pthread_mutex_init(&shareStruct->lock,NULL);
 58  58     pthread_cond_init(&shareStruct->notEmpty,NULL);
 59  59     pthread_cond_init(&shareStruct->notFull,NULL);
 60  60     shareStruct->readpos=0;
 61  61     shareStruct->writepos=0;
 62  62     memset(shareStruct->buffer, -1, sizeof(int)*BUFF_SIZE); // -1 表示未写入数据
 63  63 }
 64  64 
 65  65 void* ProducterConsumer::producer(void* arg)
 66  66 {
 67  67     int data = 0;
 68  68     while(!m_isStop)
 69  69     {
 70  70         writeIn(&m_prodconsStruct, data);
 71  71         data++;
 72  72     }
 73  73     
 74  74     return NULL;
 75  75 }
 76  76 
 77  77 void* ProducterConsumer::consumer(void* threadNum)
 78  78 {
 79  79     while(!m_isStop)    // C语言无bool类型,也就无true和false
 80  80     {
 81  81         readOut(&m_prodconsStruct,(int)threadNum);
 82  82     }
 83  83     
 84  84     return NULL;
 85  85 }
 86  86 
 87  87 void ProducterConsumer::writeIn(prodcons_t *shareStruct,int data)
 88  88 {
 89  89     pthread_mutex_lock(&shareStruct->lock);
 90  90     
 91  91     /*
 92  92     写指针追上读指针并且写指针指向的下一个缓存空间有数据,则表示缓存被写满,此时不可再写,否则会覆盖未读数据,
 93  93     我们对已经读过的缓存清零(即赋值-1),以此判断是否是写满状态,另一种方案是读写指针用一直累加的方法判断谁前谁后从而知道写满的状态
 94  94     */
 95  95     while((shareStruct->writepos == shareStruct->readpos) 
 96  96         && (shareStruct->buffer[(shareStruct->writepos+1)%BUFF_SIZE] != -1) 
 97  97         && !m_isStop) 
 98  98     {
 99  99         printf("wait for empty space\n");
100 100         pthread_cond_wait(&shareStruct->notFull,&shareStruct->lock);
101 101     }
102 102     
103 103     if(m_isStop)
104 104     {
105 105         pthread_mutex_unlock(&shareStruct->lock);
106 106         pthread_exit((void *)2);
107 107     }
108 108     
109 109     shareStruct->buffer[shareStruct->writepos % BUFF_SIZE] = data;
110 110     printf("writeIn----->%d\n",data);
111 111     shareStruct->writepos++;
112 112     if(shareStruct->writepos >= BUFF_SIZE)  
113 113         shareStruct->writepos = 0; // 缓存存满后,从头开始再存
114 114     
115 115     pthread_cond_signal(&shareStruct->notEmpty);
116 116     pthread_mutex_unlock(&shareStruct->lock);
117 117 }
118 118 
119 119 int ProducterConsumer::readOut(prodcons_t *shareStruct, int threadNum)
120 120 {
121 121     pthread_mutex_lock(&shareStruct->lock);
122 122     
123 123     while((shareStruct->readpos == shareStruct->writepos)
124 124         && (shareStruct->buffer[(shareStruct->readpos+1)%BUFF_SIZE] == -1)
125 125         && !m_isStop) 
126 126     {
127 127         printf("wait for data, Consumer Number %d\n", threadNum);
128 128         pthread_cond_wait(&shareStruct->notEmpty, &shareStruct->lock);
129 129     }
130 130     
131 131     if(m_isStop)
132 132     {
133 133         pthread_mutex_unlock(&shareStruct->lock);
134 134         pthread_exit((void *)2);
135 135     }
136 136     
137 137     int data = shareStruct->buffer[shareStruct->readpos % BUFF_SIZE];
138 138     printf("Consumer Number %d thread : 0x%0x and data = %d\n",threadNum,((unsigned int)pthread_self()), data);
139 139     shareStruct->buffer[shareStruct->readpos % BUFF_SIZE] = -1;    // 读之后清数据
140 140     shareStruct->readpos++;
141 141     if(shareStruct->readpos >= BUFF_SIZE)  
142 142         shareStruct->readpos=0; // 缓存读完后,从头再读
143 143     
144 144     pthread_cond_signal(&shareStruct->notFull);
145 145     pthread_mutex_unlock(&shareStruct->lock);
146 146     return data;
147 147 }
148 148 
149 149 void ProducterConsumer::createThread()
150 150 {
151 151     pthread_create(&m_pidPro,NULL, producer, NULL);
152 152     for(int i=0; i < CONSUMER_NUM; i++)
153 153     {
154 154         pthread_create(&m_pidCon[i],NULL, consumer,(void*)i);
155 155     }
156 156 }
157 157 
158 158 void ProducterConsumer::stopThread()
159 159 {
160 160     int err = -1;
161 161     void* ret;
162 162     m_isStop = true;
163 163     pthread_cond_broadcast(&m_prodconsStruct.notEmpty);
164 164     pthread_cond_broadcast(&m_prodconsStruct.notFull);
165 165     err = pthread_join(m_pidPro,&ret);
166 166     if(err != 0)
167 167         printf("can not join producter thread :0x%0x\n", m_pidPro);
168 168     else
169 169         printf("exit producter thread :0x%0x, exit code: %d\n", m_pidPro, (int)ret);
170 170     
171 171     for(int i = 0; i < CONSUMER_NUM; i++)
172 172     {
173 173         err = pthread_join(m_pidCon[i],&ret);
174 174         if(err != 0)
175 175             printf("can not join consumer thread :0x%0x\n", m_pidCon[i]);
176 176         else
177 177             printf("exit consumer thread :0x%0x, exit code: %d\n", m_pidCon[i], (int)ret);
178 178     }
179 179 }
180 180 
181 181 int main(void)
182 182 {
183 183     ProducterConsumer pc;
184 184     printf("start...\n");
185 185     
186 186     // 延迟-----决定线程跑多久
187 187     struct timeval timeout;
188 188     timeout.tv_sec = 1;    // 1s
189 189     timeout.tv_usec = 0;
190 190     select(0, NULL, NULL, NULL, &timeout);
191 191     
192 192     pc.stopThread();
193 193     printf("end...\n");
194 194     exit(0);
195 195 }
196 196 
197 197 /*
198 198 1.可以将输出打印到文件中查看,命令如下:
199 199     $./hhd_producter_and_consumer > logs.log   文件末尾而不是覆盖
200 200     $./hhd_producter_and_consumer >> logs.log  覆盖之前文件
201 201     
202 202 2.类的static变量在程序进入main()函数前初始化.
203 203 3.线程执行函数中类中必须定义为static类型,原因貌似是线程执行函数必须是普通函数,而类的成员函数依赖类的实例对象,
204 204   需要加static改变这种依赖成为全局函数,在C代码中线程执行函数无需加static.
205 205 */
View Code

C语言实现:

  1 1 #include <stdio.h>
  2   2 #include <stdlib.h>
  3   3 #include <pthread.h>
  4   4 #include <unistd.h>
  5   5 #include <sys/select.h>
  6   6 #include <string.h>
  7   7 
  8   8 #define BUFF_SIZE 16    // 缓存区大小
  9   9 #define CONSUMER_NUM 3    // 消费者人数
 10  10 
 11  11 int isStop = 0;        // 判断停止线程
 12  12 
 13  13 struct prodcons 
 14  14 {
 15  15     int buffer[BUFF_SIZE];
 16  16     pthread_mutex_t lock;
 17  17     int readpos,writepos;
 18  18     pthread_cond_t notEmpty;
 19  19     pthread_cond_t notFull;
 20  20 }m_prodconsStruct;
 21  21 
 22  22 typedef struct prodcons prodcons_t;
 23  23 
 24  24 void initial(struct prodcons* shareStruct)
 25  25 {
 26  26     pthread_mutex_init(&shareStruct->lock,NULL);
 27  27     pthread_cond_init(&shareStruct->notEmpty,NULL);
 28  28     pthread_cond_init(&shareStruct->notFull,NULL);
 29  29     shareStruct->readpos=0;
 30  30     shareStruct->writepos=0;
 31  31     memset(shareStruct->buffer, -1, sizeof(int)*BUFF_SIZE); // -1 表示未写入数据
 32  32 }
 33  33 
 34  34 void writeIn(prodcons_t *shareStruct,int data)
 35  35 {
 36  36     pthread_mutex_lock(&shareStruct->lock);
 37  37     
 38  38     /*
 39  39     线程挂起条件:
 40  40     对写指针而言,缓存是环形。
 41  41     1.写指针追上读指针表示缓存被写满,此时不可再写,否则会覆盖未读数据;
 42  42     2.收到线程停止指令;
 43  43     此处是对已经读过的缓存清零以便下次写时判断是否是写满状态,另一方案读写指针用一直累加的方法判断谁前谁后.
 44  44     */
 45  45     while((shareStruct->writepos == shareStruct->readpos) 
 46  46         && (shareStruct->buffer[(shareStruct->writepos+1)%BUFF_SIZE] != -1) 
 47  47         && !isStop) 
 48  48     {
 49  49         printf("wait for empty space\n");
 50  50         pthread_cond_wait(&shareStruct->notFull,&shareStruct->lock);
 51  51     }
 52  52     
 53  53     if(isStop)
 54  54     {
 55  55         pthread_mutex_unlock(&shareStruct->lock);
 56  56         pthread_exit((void *)2);
 57  57     }
 58  58     
 59  59     shareStruct->buffer[shareStruct->writepos % BUFF_SIZE] = data;
 60  60     printf("writeIn----->%d\n",data);
 61  61     shareStruct->writepos++;
 62  62     if(shareStruct->writepos >= BUFF_SIZE)  
 63  63         shareStruct->writepos = 0; // 缓存存满后,从头开始再存
 64  64     
 65  65     pthread_cond_signal(&shareStruct->notEmpty);
 66  66     pthread_mutex_unlock(&shareStruct->lock);
 67  67 }
 68  68 
 69  69 int readOut(prodcons_t *shareStruct, int threadNum)
 70  70 {
 71  71     pthread_mutex_lock(&shareStruct->lock);
 72  72     
 73  73     while((shareStruct->readpos == shareStruct->writepos)
 74  74         && (shareStruct->buffer[(shareStruct->readpos+1)%BUFF_SIZE] == -1)
 75  75         && !isStop) 
 76  76     {
 77  77         printf("wait for data, Consumer Number %d\n", threadNum);
 78  78         pthread_cond_wait(&shareStruct->notEmpty, &shareStruct->lock);
 79  79     }
 80  80     
 81  81     if(isStop)
 82  82     {
 83  83         pthread_mutex_unlock(&shareStruct->lock);
 84  84         pthread_exit((void *)2);
 85  85     }
 86  86     
 87  87     int data = shareStruct->buffer[shareStruct->readpos % BUFF_SIZE];
 88  88     printf("Consumer Number %d thread : 0x%0x and data = %d\n",threadNum,((unsigned int)pthread_self()), data);
 89  89     shareStruct->buffer[shareStruct->readpos % BUFF_SIZE] = -1;    // 读之后清数据
 90  90     shareStruct->readpos++;
 91  91     if(shareStruct->readpos >= BUFF_SIZE)  
 92  92         shareStruct->readpos=0; // 缓存读完后,从头再读
 93  93     
 94  94     pthread_cond_signal(&shareStruct->notFull);
 95  95     pthread_mutex_unlock(&shareStruct->lock);
 96  96     return data;
 97  97 }
 98  98 
 99  99 void* producer(void* arg)
100 100 {
101 101     int data = 0;
102 102     while(1)
103 103     {
104 104         writeIn(&m_prodconsStruct, data);
105 105         data++;
106 106     }
107 107     
108 108     return NULL;
109 109 }
110 110 
111 111 void* consumer(void* threadNum)
112 112 {
113 113     while(1)    // C语言无bool类型,也就无true和false
114 114     {
115 115         readOut(&m_prodconsStruct,(int)threadNum);
116 116     }
117 117     
118 118     return NULL;
119 119 }
120 120 
121 121 int main(void)
122 122 {
123 123     int err = -1;
124 124     void* ret;
125 125     pthread_t pid_pro;
126 126     pthread_t pid_con[CONSUMER_NUM];
127 127     
128 128     // 初始化共享结构体
129 129     initial(&m_prodconsStruct);
130 130     
131 131     // 创建生产者和消费者
132 132     pthread_create(&pid_pro,NULL,producer, NULL);
133 133     for(int i=0; i < CONSUMER_NUM; i++)
134 134     {
135 135         pthread_create(&pid_con[i],NULL,consumer,(void*)i);
136 136     }
137 137     
138 138     // 延迟-----觉得线程能跑多久
139 139     struct timeval timeout;
140 140     timeout.tv_sec = 1;    // 1s
141 141     timeout.tv_usec = 0;
142 142     select(0, NULL, NULL, NULL, &timeout);
143 143     
144 144     // 销毁生产者消费者线程
145 145     isStop = 1;
146 146     pthread_cond_broadcast(&m_prodconsStruct.notEmpty);
147 147     pthread_cond_broadcast(&m_prodconsStruct.notFull);
148 148     err = pthread_join(pid_pro,&ret);
149 149     if(err != 0)
150 150         printf("can not join producter thread :0x%0x\n", pid_pro);
151 151     else
152 152         printf("exit producter thread :0x%0x, exit code: %d\n", pid_pro, (int)ret);
153 153     
154 154     for(int i = 0; i < CONSUMER_NUM; i++)
155 155     {
156 156         err = pthread_join(pid_con[i],&ret);
157 157         if(err != 0)
158 158             printf("can not join consumer thread :0x%0x\n", pid_con[i]);
159 159         else
160 160             printf("exit consumer thread :0x%0x, exit code: %d\n", pid_con[i], (int)ret);
161 161     }
162 162 
163 163     printf("end...\n");
164 164     exit(0);
165 165 }
View Code

posted on 2015-12-02 18:13  BlueSky~  阅读(966)  评论(0编辑  收藏  举报

导航