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目录下的文件,可以看到打印出来了我们想要的信息,也就是产品这下完整了。

    这篇帖子就总结到这里,如有不正确的地方还请指出,大家共同进步!

0 0
原创粉丝点击