当前位置: > shell编程 >

Linux多线程编程(二)

时间:2014-09-11 18:18来源:linux.it.net.cn 作者:it
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待条件变量的条件成立而挂起(此时不再占用cpu);另一个线程使条件成立(给出条件成立信号)。

引言
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待条件变量的条件成立而挂起(此时不再占用cpu);另一个线程使条件成立(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。

函数原型
1. 定义条件变量

1 #include <pthread.h>
2  
3 /* 定义两个条件变量 */
4 pthread_cond_t cond_pro, cond_con;

2. 初始化和销毁条件变量

1 #include <pthread.h>
2  
3 int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);int pthread_cond_destroy(pthread_cond_t *cond); /* 初始化条件变量 */
4 pthread_cond_init(&cond_pro, NULL);
5 pthread_cond_init(&cond_con, NULL);
6 /* 销毁条件变量 */
7 pthread_cond_destroy(&cond_pro);
8 pthread_cond_destroy(&cond_pro);

3. 等待和激发条件

01 #include <pthread.h>
02  
03 int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
04  
05 int pthread_cond_broadcast(pthread_cond_t *cond);
06 int pthread_cond_signal(pthread_cond_t *cond);
07 /* 等待条件 */
08 /* 注意:pthread_cond_wait为阻塞函数。解开锁,再等待。等条件满足时,需要抢到锁,才可以被唤醒*/ 
09 pthread_cond_wait(&cond_pro,&mutex);
10  
11 /* 激发条件 */
12 /* 所有因为不满足条件的线程都会阻塞在条件变量cond_pro中的一个队列中 */
13 /* 以广播方式,通知所有被阻塞的所有线程 */
14 pthread_cond_broadcast(&cond_pro);
15 /* 以signal方式,只通知排在最前面的线程 */
16 pthread_cond_signal(&cond_pro);

代码

001 /*************************************************************************
002   > File Name: my_con.c
003   > Author: KrisChou
004   > Mail:zhoujx0219@163.com
005   > Created Time: Tue 26 Aug 2014 10:24:29 AM CST
006  ************************************************************************/
007  
008 #include <stdio.h>
009 #include <stdlib.h>
010 #include <string.h>
011 #include <pthread.h>
012 #include <unistd.h>
013 #define CELL 10
014 #define FLORE 0
015  
016  
017  
018 int i = 0; /* 所有线程共享的全局变量,此处假定至多递增至10,最小减到0 */
019  
020 pthread_mutex_t mutex;       /* 定义互斥锁 */
021 pthread_cond_t cond_pro, cond_con; /* 定义两个条件变量 */
022  
023 /* 生产者线程 */
024 void* pro_handler(void *arg)
025 {
026   pthread_detach(pthread_self());  /* 由系统回收线程资源,而非主线程回收资源 ,此类情况主线程是个服务器,永久不会退出 */
027   
028   while(1)
029   {
030     pthread_mutex_lock(&mutex);
031     while(i >= CELL)
032     {
033       pthread_cond_wait(&cond_pro,&mutex);
034       /* continue是轮询,此处是阻塞 */
035       /* 把锁放开再等 ,第一个参数是结构体指针,其中有成员存放被阻塞的函数 */
036       /*不占cpu*/
037       /* 不满足条件时才会等 ,需要别人告诉它,才能唤醒它*//* 当它返回时,锁也要回来了*/
038     }
039     i++;
040     if(i == 1)
041     {
042       /* 由空到不空,唤醒消费者 */
043       pthread_cond_signal(&cond_con);  /*不会立马signal被阻塞的消费者线程,因为其还要等锁抢回来*/
044     }
045     printf("add i: %d \n", i);
046     pthread_mutex_unlock(&mutex);
047     sleep(rand() % 5 + 1);
048   }
049 }
050  
051 /* 消费者线程 */
052 void* con_handler(void *arg)
053 {
054   pthread_detach(pthread_self());
055   while(1)
056   {
057     pthread_mutex_lock(&mutex);
058     while(i <= FLORE)
059     {
060       pthread_cond_wait(&cond_cno,&mutex);
061     }
062     i--;
063     if(i == 9) /* 由满到不满,要告诉生产者,以便将其唤醒 *//*此处,直接signal也可以,我们是为了更加精确*/
064     {
065       pthread_cond_signal(&cond_pro);
066     }
067     printf("con i: %d \n", i);
068     pthread_mutex_unlock(&mutex);
069     sleep(rand() % 5 + 1);
070   }
071 }
072  
073 int main(int argc, char *argv[]) // exe +num -num
074 {
075   srand(getpid());
076   int con_cnt, pro_cnt;
077   pro_cnt = atoi(argv[1]);
078   con_cnt = atoi(argv[2]);
079   pthread_mutex_init(&mutex,NULL);
080   pthread_cond_init(&cond_pro,NULL);
081   pthread_cond_init(&cond_con,NULL);
082   pthread_t *arr = (pthread_t*)calloc(con_cnt + pro_cnt , sizeof(pthread_t));
083   int index = 0;
084   while(pro_cnt > 0)
085   {
086     pthread_create(arr + index, NULL, pro_handler, NULL);
087     index++;
088     pro_cnt--;
089   }
090   while(con_cnt > 0)
091   {
092     pthread_create(arr + index, NULL, con_handler, NULL);
093     index++;
094     con_cnt--;
095   }
096   while(1);
097   pthread_mutex_destroy(&mutex);
098   pthread_cond_destroy(&cond_pro);
099   pthread_cond_destroy(&cond_con);
100   return 0;
101 }

注意
无论是在生产者线程,还是在消费者线程中。标记黄色部分的判断条件必须用while。以生产者线程举例,当i>=CELL时,也就是i满时,此时执行pthread_cond_wait(&cond_cno,&mutex); 该生产者线程被挂起。必须等到消费者线程pthread_cond_signal(&cond_pro); 将其唤醒。但是消费者将其signal还不够,被挂其的生产者线程必须重新拿到锁,才可以被激活。但是,由于在消费者signal的同时,生产者并不能立即抢到锁,所以此时可能i值又改变变为大于等于10了。因此必须用while。不然可能导致i>10。

(责任编辑:IT)
------分隔线----------------------------
栏目列表
推荐内容