linux应用编程笔记(13)信号量同步编程
来源:互联网 发布:淘宝投诉盗版书 编辑:程序博客网 时间:2024/06/05 04:13
摘要: 总结了进程间同步的机制,如何利用同步机制处理消费者和生产者的问题,最后用实例加深了理解。
一、什么是进程间的同步
进程间的同步,指的是一组并发进程,相互合作,相互等待,使得各自按照一定的顺序执行的过程称为进程间的同步。
二、生产者消费者的问题
这个问题的描述如下:有一群生产者进程在生产消息,并将此 消息提供给消费者进程去消费。为使生产者进程和消费者进程能 并发进行,在他们之间设置了一个具有一个或多个缓冲区的缓冲池,生产者进程可以将它所生产的消息放入一个缓冲区中,消费者进程可以从一个缓冲区中取得一个消息消费。
那么这个过程会出现什么问题呢?如果消费者消费者消费完了,生产者还没有生产出来,那么消费者就会一直等待。反过来,生产者一直生产,但是消费者没有去消费,那么缓冲区就会满了,生产者也会停止。
常见的解决这个问题的方法就是信号量的同步编程。
三、不带信号量同步编程的生产者和消费者程序
这个过程需要三个文件,生产者,消费者和缓冲区,这里缓冲区我们用一个文件。也就是producer.c consumer.c和product.txt
producer.c做哪些事情呢?就是创建缓冲区,即product.txt,然后休息,这里的休息其实是模仿我们在实际进程当中遇到的没有生产出来,这样可以看到系统出现的故障现象,休息完了之后我们再往里写东西。
consumer.c做的事情就很简单了,就是打开缓冲区文件,然后读走数据,也就是消费的意思了。
下面在同一个文件夹下面创建这三个文件,producer.c文件内容如下:#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#include <unistd.h>#include <error.h> int main(void){ int fd; /*打开文件产品*/ fd=open("./product.txt",O_RDWR); if(fd==-1) { printf("openerror!\n"); exit(0); } /*休息*/ sleep(20); /*向文件里写入内容*/ write(fd,"myproduct",20); /*关闭文件*/ close(fd); return 0; } 编译运行以后可以看到producer会休息20S,然后这时候我们编写消费者的程序。consumer.c如下:#include <stdlib.h>#include <stdio.h> int main(void){ system("cp./product.txt ./ship/"); return0; }
这里使用了一个系统调用,可以调用命令cp把当前目录下的产品复制到当前目录下的ship目录下,如果生产者在休息,但是还是被拷贝走了,我们的产品就是不完整的,就会出错误。
这里编译运行之后看效果,首先运行producer然后紧接着运行consumer,这时候切到ship目录下免去看拷贝的product,里面是空的,这样就说明不行了,他们之间没有一个机制保证一个生产好了,另一个采取拿,那一个拿完了,另一个紧接着生产,如此循环才是正确的生产者和消费者的关系。
四、利用信号量同步机制的生产者消费者问题
其实这个同步机制很简单,我们在互斥的时候是先获得信号量,再释放,这里同步初始值为0,互斥初始值为1,也就是在生产者一开始先创建一个信号量,再生产者生产完毕之后,我们在释放,然后消费者那里,就是获取信号量,这样只有生产者生产完了消费者才会拿到消费产品。
程序如下:
<span style="font-size:18px;"><strong>producer</strong>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <sys/ipc.h>#include <sys/sem.h> int main(void){ int fd; key_t key;//键值 int semid; int retval; struct sembuf sops; /*创建信号量*/ key= ftok("/home/passionbird",2);//这里可以利用一个目录创建多个键值,只要他们的项目编号不一样就可以 semid=semget(key,1,IPC_CREAT);//将键值传入,我们这里信号量集合里就只有一个信号量,因为还没有,所以需要创建,加上IPC_CREAT /*设置信号量的初始值*/ retval=semctl(semid,0,SETVAL,0);//设置为0,此处是同步操作 printf("theinit value is:%d\n",retval);//两处打印是为了确保初始值为0 /*打开文件产品*/ fd=open("./product.txt",O_RDWR); if(fd==-1) { printf("openerror!\n"); exit(0); } /*休息*/ sleep(20); /*向文件里写入内容*/ write(fd,"myproduct",20); /*释放信号量*/ sops.sem_num= 0;//因为只有一个信号量,所以在操作数组中的编号为0 sops.sem_op= +1;//+1即释放了信号量,写成+1是为了便于理解 sops.sem_flg= SEM_UNDO;//sop的第三个参数 semop(semid,&sops,1); retval=semctl(semid,0,GETVAL);//设置为0,此处是同步操作 printf("theinit value is:%d\n",retval);//两处打印是为了确保初始值为0 /*关闭文件*/ close(fd); return 0; }</span>
<span style="font-size:18px;"><strong>consumer</strong>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <sys/ipc.h>#include <sys/sem.h> int main(void){ key_t key; int semid; int retval; struct sembuf sops; /*先打开信号量集合*/ key= ftok("/home/passionbird",2);//利用相同的键值可以关联同一个信号量 semid=semget(key,1,IPC_CREAT);//将键值传入,使得a,b打开的信号量是同一个信号量,这里已经有了不会再创建 /*获取信号量*/ sops.sem_num= 0;//因为只有一个信号量,所以在操作数组中的编号为0 sops.sem_op= -1;//-1即获取走了信号量 sops.sem_flg= SEM_UNDO;//sop的第三个参数 semop(semid,&sops,1); //传入返回的semid retval=semctl(semid,0,GETVAL); printf("theinit value is:%d\n",retval); /*取走产品*/ system("cp./product.txt ./ship/"); return 0; }</span>
最终查看ship目录下的文件,可以看到打印出来了我们想要的信息,也就是产品这下完整了。
这篇帖子就总结到这里,如有不正确的地方还请指出,大家共同进步!
- linux应用编程笔记(13)信号量同步编程
- Linux 信号量同步编程
- 【Linux】 多线程编程(信号量实现同步)
- Linux多线程编程入门-同步机制-信号量
- linux系统编程:线程同步-信号量(semaphore)
- 【Linux信号通讯编程】信号量同步
- 信号量--进程同步编程
- 信号量同步编程
- 信号量同步编程
- 信号量同步编程
- Linux多线程编程之同步对象编程:线程信号量
- linux应用编程笔记(12)信号量详解及互斥编程
- linux应用编程:signal(信号量) 实例1
- linux应用开发-信号量互斥编程
- linux下编程学习----- 线程同步之无名信号量
- linux下编程学习----- 线程同步之无名信号量
- linux下编程学习----- 线程同步之无名信号量
- linux 多线程编程 之 信号量互斥同步
- Android Paint和Canvas常用方法和效果
- 这个月小结
- 南大软院大神养成计划——第十一天
- Go struct
- 自定义标题栏
- linux应用编程笔记(13)信号量同步编程
- Maven构建一个最简单的Spring Boot + Spring MVC项目
- MyBatis中的OGNL教程
- eclpise编辑器主题配置文件的使用方法
- 递归基础练习
- 蓝懿 iOS 技术交流和心得分享 11.26
- 树莓派无法DHMI输出的问题
- SpringMVC中HandlerMethod的请求参数解析过程
- 统领团队 你可知这些?论游戏开发团队管理