




已阅读5页,还剩4页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
下面的程式是经典的生产者/消费者的例证。#include #include #include #define MAX 5pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; /*初始化互斥锁*/pthread_cond_t=PTHREAD_CODE_INITIALIZER; /*初始化条件变量*/typedef structchar bufferMAX;int how_many;BUFFER;BUFFER share=“”,0;char ch=A;/*初始化ch*/void *read_some(void *);void *write_some(void *);int main(void)pthread_t t_read;pthread_t t_write;pthread_create(&t_read,NULL,read_some,(void *)NULL); /*创建进程t_a*/pthread_create(&t_write,NULL,write_some,(void *)NULL); /*创建进程t_b*/pthread_join(t_write,(void *)NULL);pthread_mutex_destroy(&mutex);pthread_cond_destroy(&cond);exit(0);void *read_some(void *junk)int n=0;printf(“R %2d: startingn”,pthread_self();while(ch!=Z) pthread_mutex_lock(&lock_it);/*锁住互斥量*/ if(share.how_many!=MAX) share.buffershare.how_many+=ch+;/*把字母读入缓存*/ printf(“R %2d:Got char%cn”,pthread_self(),ch-1);/*打印读入字母*/ if(share.how_many=MAX) printf(“R %2d:signaling fulln”,pthread_self(); pthread_cond_signal(&write_it);/*假如缓存中的字母到达了最大值就发送信号*/ pthread_mutex_unlock(&lock_it);/*解锁互斥量*/ sleep(1);printf(“R %2d:Exitingn”,pthread_self();return NULL;void *write_some(void *junk)int i;int n=0;printf(“w %2d: startingn”,pthread_self();while(ch!=Z) pthread_mutex_lock(&lock_it);/*锁住互斥量*/ printf(“nW %2d:Waitingn”,pthread_self(); while(share.how_many!=MAX)/*假如缓存区字母不等于最大值就等待*/ pthread_cond_wait(&write_it,&lock_it); printf(“W %2d:writing buffern”,pthread_self(); for(i=0;share.buffer&share.how_many;+i,share.how_many-) putchar(share.buffer); /*循环输出缓存区字母*/ pthread_mutex_unlock(&lock_it);/*解锁互斥量*/printf(“W %2d:exitingn”,pthread_self();return NULL;程式每读入5个字母,打印一遍,并清空缓存区,循环执行直到Y为止。程式运行结果如下:#cc lpthread o readandwrite readandwrite.c#./readandwrireR 1082330304: stareingW 1090718784:stringW 1090718784:WaitingR 1082330304:Got charAR 1082330304:Got charBR 1082330304:Got charCR 1082330304:Got charDR 1082330304:Got charER 1082330304:signaling fullW 1090718784:wring bufferABCDEW 1090718784:WaitingR 1082330304:Got charF三、条件变量属性 使用条件变量之前要先进行初始化。能够像我们前面那样可静态初始化pthread_cond_t my_condition=PTHREAD_COND_INITIALIZER;也能够利用函数pthread_cond_init动态初始化。条件变量 属性类型为pthread_condattr_t,他们由以下函数初始化或摧毁。11名称::pthread_condattr_init/pthread_condattr_destroy功能:初始化/回收pthread_condattr_t结构头文档:#include 函数原形:int pthread_condattr_init(pthread_condattr_t *attr);int pthread_condattr_destroy(pthread_condattr_t *attr);参数:返回值:若成功返回0,若失败返回错误编号。一旦某个条件变量对象被初始化了,我们就能够利用下面函数来查看或修改特定属性了。12.名称::pthread_condattr_getpshared/pthread_condattr_setpshared功能:查看或修改条件变量属性头文档:#include 函数原形:int pthread_condattr_init(const pthread_condattr_t *restrict attr);int pthread_condattr_destroy(pthread_rwlockattr_t *attr,int pshared);参数:返回值:若成功返回0,若失败返回错误编号。pthread_condattr_getpshared函数在由valptr指向的整数中返回这个属性的当前 值,pthread_condattr_setpshared则根据value的值配置这个属性的当前值。value的值能够是 PTHREAD_PROCESS_PRIVATE或PTHREAD_PROCESS_SHARED(进程间共享).四、条件变量和互斥锁、信号量的区别到这里,我们把posix的互斥锁、信号量、条件变量都介绍完了,下面我们来比较一下他们。 1.互斥锁必须总是由给他上锁的线程解锁,信号量的挂出即不必由执行过他的等待操作的同一进程执行。一个线程能够等待某个给定信号灯,而另一个线程能够挂出该信号灯。 2.互斥锁要么锁住,要么被解开(二值状态,类型二值信号量)。 3.由于信号量有一个和之关联的状态(他的计数值),信号量挂出操作总是被记住。然而当向一个条件变量发送信号时,假如没有线程等待在该条件变量上,那么该信号将丢失。 4.互斥锁是为了上锁而优化的,条件变量是为了等待而优化的,信号灯即可用于上锁,也可用于等待,因而可能导致更多的开销和更高的复杂性。转自湖光倒影/u/22935/showart_340463.html(转自)/u1/41332/showart_341103.html条件变量 使用互斥锁来实现线程间数据的共享和通信,互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程 发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发 生变化。一旦其它的某个线程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的线程。这些线程将重新锁定互斥锁并重新测试条件是 否满足。一般说来,条件变量被用来进行线承间的同步。条件变量的结构为pthread_cond_t,函数pthread_cond_init()被用来初始化一个条件变量。它的原型为:extern int pthread_cond_init _P (pthread_cond_t *_cond,_const pthread_condattr_t *_cond_attr);其中cond是一个指向结构pthread_cond_t的指针,cond_attr是一个指向结构pthread_condattr_t的指 针。结构 pthread_condattr_t是条件变量的属性结构,和互斥锁一样我们可以用它来设置条件变量是进程内可用还是进程间可用,默认值是 PTHREAD_ PROCESS_PRIVATE,即此条件变量被同一进程内的各个线程使用。注意初始化条件变量只有未被使用时才能重新初始化或被释放。释放一个条件变量 的函数为pthread_cond_ destroy(pthread_cond_t cond)。函数pthread_cond_wait()使线程阻塞在一个条件变量上。它的函数原型为:extern int pthread_cond_wait _P (pthread_cond_t *_cond,pthread_mutex_t *_mutex);线程解开mutex指向的锁并被条件变量cond阻塞。线程可以被函数pthread_cond_signal和函数 pthread_cond_broadcast唤醒,但是要注意的是,条件变量只是起阻塞和唤醒线程的作用,具体的判断条件还需用户给出,例如一个变量是 否为0等等,这一点我们从后面的例子中可以看到。线程被唤醒后,它将重新检查判断条件是否满足,如果还不满足,一般说来线程应该仍阻塞在这里,被等待被下 一次唤醒。这个过程一般用while语句实现。另一个用来阻塞线程的函数是pthread_cond_timedwait(),它的原型为:extern int pthread_cond_timedwait _P (pthread_cond_t *_cond,pthread_mutex_t *_mutex, _const struct timespec *_abstime);它比函数pthread_cond_wait()多了一个时间参数,经历abstime段时间后,即使条件变量不满足,阻塞也被解除。函数pthread_cond_signal()的原型为:extern int pthread_cond_signal _P (pthread_cond_t *_cond);它用来释放被阻塞在条件变量cond上的一个线程。多个线程阻塞在此条件变量上时,哪一个线程被唤醒是由线程的调度策略所决定的。要注意的是, 必须用保护条件变量的互斥锁来保护这个函数,否则条件满足信号又可能在测试条件和调用pthread_cond_wait函数之间被发出,从而造成无限制 的等待。下面是使用函数pthread_cond_wait()和函数pthread_cond_signal()的一个简单的例子。pthread_mutex_t count_lock;pthread_cond_t count_nonzero;unsigned count;decrement_count() pthread_mutex_lock (&count_lock);while(count=0)pthread_cond_wait( &count_nonzero, &count_lock);count=count -1;pthread_mutex_unlock (&count_lock);increment_count()pthread_mutex_lock(&count_lock);if(count=0)pthread_cond_signal(&count_nonzero);count=count+1;pthread_mutex_unlock(&count_lock);count值为0时,decrement函数在pthread_cond_wait处被阻塞,并打开互斥锁count_lock。此时,当调用 到函数 increment_count时,pthread_cond_signal()函数改变条件变量,告知decrement_count()停止阻塞。读 者可以试着让两个线程分别运行这两个函数,看看会出现什么样的结果。函数pthread_cond_broadcast(pthread_cond_t *cond)用来唤醒所有被阻塞在条件变量cond上的线程。这些线程被唤醒后将再次竞争相应的互斥锁,所以必须小心使用这个函数。信号量信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。当公共资源增加时,调用函数sem_post()增加信号量。只有当信号 量值大于时,才能使用公共资源,使用后,函数sem_wait()减少信号量。函数sem_trywait()和函数pthread_ mutex_trylock()起同样的作用,它是函数sem_wait()的非阻塞版本。下面我们逐个介绍和信号量有关的一些函数,它们都在头文件 /usr/include/semaphore.h中定义。信号量的数据类型为结构sem_t,它本质上是一个长整型的数。函数sem_init()用来初始化一个信号量。它的原型为:extern int sem_init _P (sem_t *_sem, int _pshared, unsigned int _value);sem为指向信号量结构的一个指针;pshared不为时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。函数sem_post( sem_t *sem )用来增加信号量的值。当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。函数sem_destroy(sem_t *sem)用来释放信号量sem。下面我们来看一个使用信号量的例子。在这个例子中,一共有4个线程,其中两个线程负责从文件读取数据到公共的缓冲区,另两个线程从缓冲区读取数据作不同的处理(加和乘运算)。/* File sem.c */#include stdio.h#include pthread.h#include semaphore.h#define MAXSTACK 100int stackMAXSTACK2;int size=0;sem_t sem;/* 从文件1.dat读取数据,每读一次,信号量加一*/void ReadData1(void)FILE *fp=fopen(1.dat,r);while(!feof(fp)fscanf(fp,%d %d,&stacksize0,&stacksize1);sem_post(&sem);+size;fclose(fp);/*从文件2.dat读取数据*/void ReadData2(void)FILE *fp=fopen(2.dat,r);while(!feof(fp)fscanf(fp,%d %d,&stacksize0,&stacksize1);sem_post(&sem);+size;fclose(fp);/*阻塞等待缓冲区有数据,读取数据后,释放空间,继续等待*/void HandleData1(void)while(1)sem_wait(&sem);printf(Plus:%d+%d=%dn,stacksize0,stacksize1,stacksize0+stacksize1);-size;void HandleData2(void)while(1)sem_w
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年数据分析师高级面试题集
- 桡尺骨骨折课件
- 2025年图书馆特色资源建设方案策划师招聘面试题解
- 2025年双语数学教学职位应聘面试攻略模拟题及答案解析民办学校
- 2025年区域经济与可持续发展考试试题及答案
- 2025年电力行业安全监理员招聘安全知识预测试题集
- 2026届湖南省邵阳市邵阳县第一中学化学高三上期末教学质量检测试题含解析
- 2026届河南省扶沟高中化学高二第一学期期末考试模拟试题含答案
- 2025年法律行业人工智能应用考察试卷及解析答案
- 2025年注册验船师资格考试(A级船舶检验专业综合能力)综合试题及答案一
- 2025年广西南宁市宾阳县公开招聘乡村医生73人笔试备考试题及答案解析
- 2025年保安员理论考试题库及答案
- 2025年江苏省综合评标评审专家库专家考试(公共基础知识)历年参考题库含答案详解(5套)
- 2025废气处理合作协议合同范本
- 麻醉师进修汇报
- 基坑监测评审汇报
- 2025-2026年秋季学期各周国旗下讲话安排表+2025-2026学年上学期升旗仪式演讲主题安排表
- 物业公司电瓶车管理制度
- 肺占位性病变护理查房
- 广告创意与用户体验-第3篇-洞察阐释
- 幼儿园一日常规安全培训
评论
0/150
提交评论