linux应用编程笔记(13)信号量同步编程
2015-11-26 21:50
453 查看
摘要: 总结了进程间同步的机制,如何利用同步机制处理消费者和生产者的问题,最后用实例加深了理解。
一、什么是进程间的同步
进程间的同步,指的是一组并发进程,相互合作,相互等待,使得各自按照一定的顺序执行的过程称为进程间的同步。
二、生产者消费者的问题
这个问题的描述如下:有一群生产者进程在生产消息,并将此 消息提供给消费者进程去消费。为使生产者进程和消费者进程能 并发进行,在他们之间设置了一个具有一个或多个缓冲区的缓冲池,生产者进程可以将它所生产的消息放入一个缓冲区中,消费者进程可以从一个缓冲区中取得一个消息消费。
那么这个过程会出现什么问题呢?如果消费者消费者消费完了,生产者还没有生产出来,那么消费者就会一直等待。反过来,生产者一直生产,但是消费者没有去消费,那么缓冲区就会满了,生产者也会停止。
常见的解决这个问题的方法就是信号量的同步编程。
三、不带信号量同步编程的生产者和消费者程序
这个过程需要三个文件,生产者,消费者和缓冲区,这里缓冲区我们用一个文件。也就是producer.c consumer.c和product.txt
producer.c做哪些事情呢?就是创建缓冲区,即product.txt,然后休息,这里的休息其实是模仿我们在实际进程当中遇到的没有生产出来,这样可以看到系统出现的故障现象,休息完了之后我们再往里写东西。
consumer.c做的事情就很简单了,就是打开缓冲区文件,然后读走数据,也就是消费的意思了。
这里使用了一个系统调用,可以调用命令cp把当前目录下的产品复制到当前目录下的ship目录下,如果生产者在休息,但是还是被拷贝走了,我们的产品就是不完整的,就会出错误。
这里编译运行之后看效果,首先运行producer然后紧接着运行consumer,这时候切到ship目录下免去看拷贝的product,里面是空的,这样就说明不行了,他们之间没有一个机制保证一个生产好了,另一个采取拿,那一个拿完了,另一个紧接着生产,如此循环才是正确的生产者和消费者的关系。
四、利用信号量同步机制的生产者消费者问题
其实这个同步机制很简单,我们在互斥的时候是先获得信号量,再释放,这里同步初始值为0,互斥初始值为1,也就是在生产者一开始先创建一个信号量,再生产者生产完毕之后,我们在释放,然后消费者那里,就是获取信号量,这样只有生产者生产完了消费者才会拿到消费产品。
程序如下:
最终查看ship目录下的文件,可以看到打印出来了我们想要的信息,也就是产品这下完整了。
这篇帖子就总结到这里,如有不正确的地方还请指出,大家共同进步!
一、什么是进程间的同步
进程间的同步,指的是一组并发进程,相互合作,相互等待,使得各自按照一定的顺序执行的过程称为进程间的同步。
二、生产者消费者的问题
这个问题的描述如下:有一群生产者进程在生产消息,并将此 消息提供给消费者进程去消费。为使生产者进程和消费者进程能 并发进行,在他们之间设置了一个具有一个或多个缓冲区的缓冲池,生产者进程可以将它所生产的消息放入一个缓冲区中,消费者进程可以从一个缓冲区中取得一个消息消费。
那么这个过程会出现什么问题呢?如果消费者消费者消费完了,生产者还没有生产出来,那么消费者就会一直等待。反过来,生产者一直生产,但是消费者没有去消费,那么缓冲区就会满了,生产者也会停止。
常见的解决这个问题的方法就是信号量的同步编程。
三、不带信号量同步编程的生产者和消费者程序
这个过程需要三个文件,生产者,消费者和缓冲区,这里缓冲区我们用一个文件。也就是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日志清理工具:Logclean-ng编译
- Linux日志清理工具:Logclean-ng编译
- 使用Centos6.3-32bit + vsftpd 来搭建FTP服务器
- Linux_ISCSI服务器
- Linux内核笔记--内存管理之用户态进程内存分配
- centos7安装vncserver
- 基于int的Linux的经典系统调用实现
- linux应用编程笔记(12)信号量详解及互斥编程
- Perf -- Linux下的系统性能调优工具
- centos 部署内容
- linux 远程工具
- Linux Performance Analysis and Tools(Linux性能分析和工具)
- linux python pip 安装
- syslinux
- 安装完成ubuntu系统后的基本的相关配置---Linux总结笔记
- Linux后台运行过程查看
- 原来今天是感恩节-Linux基础继续&MySQL和PHP
- pxelinux.0
- 将Centos的yum源更换为国内的阿里云源
- linux 根据当前日期获取上个季度的第一天和最后一天