Linux 信号量同步编程

前一篇文章概述了Linux 系统中信号量互斥编程,这篇文章正好是前一篇的姊妹篇----信号量同步。说它们是姊妹篇是由于它们都是利用了内核的信号量机制实现了进程间的通讯。由于二者所解决的问题不一样,所以它们使用的场景就会有所区别。编程

信号量互斥主要解决的问题是:进程间须要同时访问某种资源,可是它们对资源的操做会互相影响对方的操做结果,所以须要一种机制实现让进程在访问资源时能禁止其余进程访问相同的资源。而信号量同步则解决了另外一个经典问题:生产者和消费者之间的协同工做问题。app

首先描述一下生产者和消费者问题:进程A 负责生产产品(建立并写入文件),进程B 负责消费产品(复制文件),理想的流程是当进程A 建立并写好数据到文件之后,进程B就取走文件。可是两个进程运行时机的不肯定每每让这个流程出现混乱,即进程A的生产工做还未完成(如只建立了文件可是没写入数据),进程B 就复制了文件,致使进程B 获得的是一个不完整的文件。事实上问题出现的缘由就是两个进程间没有一种同步的机制。ide

信号量的提出就解决了这个问题。信号量的实如今前一篇文章中有详细介绍,这里只是指出运用信号量同步进程与互斥之间的不一样,而后给出一个实例说明。测试

下面是笔者实现代码的思惟导图:spa

与互斥不一样的是,在给信号量赋初值时并非赋值为1,而是赋值为0,而且在生产者中并无获取信号量,而在消费者中也没有释放信号量。这样作是为了使二者的运行次序不会影响最后的结果。code

能够分析:若是生产者程序先运行,它会依次建立并写入文件,假设此时消费者程序运行,可是此时信号量初值为0,所以消费者程序被挂起。当生产者程序执行完,释放信号量之后,消费者程序继续运行,最后获得正确的文件。blog

若是消费者程序先运行,它测试到信号量初值是0 ,所以直接被挂起,直到生产者程序运行完才继续运行,可知这样也可以获得正确的文件。进程

须要注意的是,在上图中的1.7 释放信号量里面,包含一个将初值置为0 的操做,这样是为了在下一次再运行这两个程序时,若是先运行消费者,初值仍然是0。ip

下面是笔者的测试代码:资源

生产者代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main(int argc, char **argv)
{
    int fd = 0;
    key_t key;
    int semid;
    struct sembuf ops;
    //建立信号量集合
    key = ftok("/home/application/semapthore",1);
    semid=semget(key,1,IPC_CREAT);
    
    //将初值置为0
    semctl(semid,0,SETVAL,0);
    
    //建立文件
    fd = open("./product.txt",O_RDWR|O_CREAT,0755);
    
    //休息
    sleep(20);
    
    //写入数据
    write(fd,"Product is finished!",21);
    
    //关闭文件
    close(fd);
    
    //释放信号量
    ops.sem_num=0;
    ops.sem_op=1;
    ops.sem_flg = SEM_UNDO;
    semop(semid,&ops,1);
    semctl(semid,0,SETVAL,0);
    return 0;    
}
View Code

消费者代码;

#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int main(int argc,char **argv)
{

    key_t key;
    int semid;
    struct sembuf ops;  
    //打开信号量集合
    key = ftok("/home/application/semapthore",1);
    semid=semget(key,1,IPC_CREAT);  
    //获取信号量
    ops.sem_num = 0;
    ops.sem_op = -1;
    ops.sem_flg = SEM_UNDO;
    semop(semid,&ops,1);
    
    //消费文件
    system("cp ./product.txt ./comsum/");
    
    return 0;    
}
View Code