随心而作 2019-12-01
目录
管道是Linux中进程间通信的一种方式。这里所说的管道主要指无名管道,它具有以下特点:
(1)创建管道
man -k pipe|grep create
man 2 pipe
int pipe(int pipefd[2]);
当一个管道建立时,它会创建两个文件描述符fds[0]和fds[1],其中fds[0]固定用于读管道,而fd[1]固定用于写管道,这样就构成了一个半双工的通道。
(2)创建子进程
通过fork()函数创建一子进程,该子进程会继承父进程所创建的管道。
(3)关闭相应描述符
为了实现父子进程之间的读写,只需把无关的读端或写端的文件描述符关闭即可。例如在下图中将父进程的写端fd[1]和子进程的读端fd[0]关闭。此时,父子进程之间就建立起了一条子进程写入父进程读取的通道。
注意:
当一个管道共享多对文件描述符时,若将其中一对读写文件描述符都删除,则该管道就失效。
(1)popen()函数简介
标准流管道将一系列的创建过程合并到一个函数popen()中完成。它所完成的工作有以下几步:
(2)popen()函数详解
使用man 3 popen
查看函数的详细使用方法如下图:
关闭用popen()创建的流管道必须使用函数pclose()来关闭该管道流
有名管道(named pipe或FIFO)克服了无名管道只能用于具有亲缘关系的进程之间、没有名字的局限性。
创建有名管道
man -k pipe | grep named
man 3 mkfifo
int mkfifo(char *pathname,mode_t mode);
- 创建成功后,使用open()、read()和write()函数进行相关操作
信号量是用来解决进程之间的同步与互斥问题的一种进程之间通信机制,包括一个称为信号量的变量和在该信号量下等待资源的进程等待队列,以及对信号量进行的两个原子操作(PV操作)。其中信号量对应于某一种资源,取一个非负的整型值。信号量值指的是当前可用的该资源的数量,若它等于0 则意味着目前没有可用的资源。
PV原子操作的具体定义如下:
(1)创建信号量
man –k semaphore
man 2 semget
int semget(key_t key,int nsem,int semflg);
参数详解
(2)初始化信号量
使用semctl()函数的SETVAL操作
(3)进行信号量的PV 操作
调用semop()函数
(4)删除不再使用的信号量
使用semclt()函数的IPC_RMID 操作
#include<stdio.h> #include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h> #include<stdlib.h> #include<unistd.h> #define DELAY_TIME 3 int main() { pid_t result; int sem_id; sem_id=semget(ftok(".",'a'),1,0666|IPC_CREAT); init_sem(sem_id,0); result=fork(); if(result==-1) { printf("Error\n"); } else if(result==0) { printf("Child process will wait for some second...\n"); sleep(DELAY_TIME); printf("The returned value is %d in the child process(PID=%d)\n",result,getpid()); // sem_v(sem_id); } else{ // sem_p(sem_id); printf("The returned value is %d in the father process(PID=%d)\n",result,getpid()); // sem_v(sem_id); // del_sem(sem_id); } exit(0); } union semum { int val; struct sem_id_ds *buf; unsigned short *array; }; int init_sem(int sem_id,int init_value) { union semum sem_union; sem_union.val=init_value; if(semctl(sem_id,0,SETVAL,sem_union)==-1) { perror("Initialize semaphore"); return -1; }return 0; } int del_sem(int sem_id) { union semum sem_union; if(semctl(sem_id,0,IPC_RMID,sem_union)==-1) { perror("Delete semaphore"); return -1; } return 0; } int sem_p(int sem_id) { struct sembuf sem_b; sem_b.sem_num=0; sem_b.sem_op=-1; sem_b.sem_flg=SEM_UNDO; if(semop(sem_id,&sem_b,1)==-1) { perror("P operation\n"); return -1; }return 0; } int sem_v(int sem_id) { struct sembuf sem_b; sem_b.sem_num=0; sem_b.sem_op=1; sem_b.sem_flg=SEM_UNDO; if(semop(sem_id,&sem_b,1)==-1) { perror("P operation\n"); return -1; }return 0; }
运行结果如下图:
分析:没有使用信号量时,进程是并发的,谁先执行由系统本身决定,而加上信号量之后,由于信号量的初始值为0,所以必须等到值为1时,才能执行sem_p,因此需要先让子进程执行sem_v,因此先输出子进程,在输出父进程。