重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
进程间通信(IPC),是指在不同进程间传播或交换信息的。其常用方式:管道(无名管道和命名管道)、消息队列、共享内存、信号、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。
平桥ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:028-86922220(备注:SSL证书合作)期待与您的合作!一、管道(无名管道)函数原型:int pipe(int pipefd[2]);
包含头文件:#include
成功调用返回0,否则返回-1;
参数pipdfd是数组,存放文件描述符;(pipefd[0]-读,pipefd[1]-写)
特点:1.它是半双工的,具有固定的读端和写端;2.只能用于具有亲缘关系进程之间的通信(父子进程或兄弟进程);3.不是普通文件,但是可以使用read、write等,不属于系统文件(即ls指令看不到该管道),只存在于内存中。
上面代码的中我们在父进程中写内容到子进程中,并且我们让父进程等待子进程。
二、管道(命名管道FIFO)函数原型:int mkfifo(const char *pathname, mode_t mode);
包含头文件:#include
、#include ; 参数1:文件路径;参数2:与open函数中mode参数一样;
成功返回0,否则返回-1;
特点:1.可以在无关进程中通信;2.以一种特殊文件形式存在于系统文件中(ls看查看到);
这里要注意的是:当 open 一个FIFO时,是否设置非阻塞标志(
O_NONBLOCK
)的区别:
若没有指定
O_NONBLOCK
(默认),只读 open 要阻塞到某个其他进程为写而打开此 FIFO。类似的,只写 open 要阻塞到某个其他进程为读而打开它。若指定了
O_NONBLOCK
,则只读 open 立即返回。而只写 open 将出错返回 -1 如果没有进程已经为读而打开该 FIFO,其errno置ENXIO。
read.c:
write.c :
read.c执行结果:
write.c执行结果:
这里我们实现了两个无关进程的通信,fife1就相当于接口。
三、消息队列消息队列是消息的链接表,存放在内核中,一个消息队列由一个标识符来标识;
函数原型:
1.int msgget(key_t key, int msgflg); //创建或打开消息队列;
成功返回队列ID,否则返回-1;
2.int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); //发送消息;
参数1:队列ID;参数2:消息相关的结构体(包括消息类型和消息内容);参数3:消息大小;参数4:取0即可(表示阻塞);
成功返回0,否则返回-1;
3.ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg); //读取消息
和msgsnd函数参数不同的是多了long msgtye,msgtye对应的就是消息类型,一般>0;
成功返回消息数据长度,否则返回-1;
4.int msgctl(int msqid, int cmd, struct msqid_ds *buf); //控制消息队列
参数1:队列ID;参数2:对消息队列控制命令;参数3:由参数2决定,一般为NULL;
成功返回0,否则返回-1;
特点:1.消息队列是面向记录的,消息具有特定的格式和特定的优先级;2.独立于发送和接收进程,进程终止消息队列和其内容不会被删除;3.可以实现消息的随机查询;
receive.c
send.c
receivc.c运行结果:
send.c运行结果:
上面代码表示:receive进程在一直等待send进程发数据,当receive进程收到数据后给send进程回应;
四、共享内存共享内存是指两个或两个以上进程共享一个给定的存储区;
函数原型:
1.int shmget(key_t key, size_t size, int shmflg); //创建或获取一个共享内存;
(当创建一个共享内存时,参数2-size需指定其大小,并且以M为单位,引用一个存在的共享内存时,size写0即可)
成功返回共享内存ID,否则返回-1;
2.void *shmat(int shmid, const void *shmaddr, int shmflg); //连接共享内存到当前进程的地址空间;
成功连接后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问;
参数1:共享内存ID;参数2:指定共享内存的空间地址(为0时由系统默认指定);参数3:与参数2相关,参赛2为0时,参数3也为0;
成功返回指向共享内存的指针(即地址),否则返回-1;
3.int shmdt(const void *shmaddr); //端口与共享内存的连接;
注意:这并不是从系统中删除该共享内存,只是当前进程不能再访问该共享内存而已;
成功返回0,否则返回-1;
4.int shmctl(int shmid, int cmd, struct shmid_ds *buf); //控制共享内存的相关信息;
参数1:共享内存ID;参数2:对共享内存控制命令;参数3:与参数2相关,控制一些信息;
成功返回0,否则返回-1;
特点:1.共享内存时最快的一种IPC,因为进程直接对内存进行存取;2.因为多个进程可以同时操作,因此需要进行同步;3.共享内存一般搭配信息量使用(同步信息);
shmwrite.c:
shmread.c:
shmwrite.c运行结果:
shmread.c运行结果:
以上代码就是使用了共享内存进行通信,大家可以发我们在shmwrite.c里面发数据时运用了sleep函数,防止共享内存提前销毁了。
五、信号信号就是软件中断,信号提供了一种异步处理事件的方法,它允许进程和内核中断其他进程,一个信号就是一条消息,它通知进程系统发生了某一种类型的事件;
信号的处理:1.忽略信号;2.捕捉信号;3.默认动作;
忽略信号:大多数信号可以使用这个方式,注意:SIGKILL和SIGSTOP信号不能被忽略;
捕捉信号:当该信号产生时,由内核来调用用户自定义的函数来实现某一种信号的处理;
默认动作:当发生该信号时,系统会自动执行;
函数原型:
信号处理函数的注册:
1.void ( *signal(int signum, void (*handler)(int)) ) (int);或者
typedef void (*sighandler_t)(int);
1.sighandler_t signal(int signum, sighandler_t handler); //设置某一信号对应动作(入门版)
再讲解这个函数之前我们先来补充一点知识——typedef用法之一:定义函数指针类型;就拿上面这个函数为例:sighandler_t是一个函数指针,其有一个整形类型的形参,并且返回值为空,使用typedef之后,sighandler_t就可以来定义一个函数,其就相当于是一个类型了(和int这种一样),所有signal函数形参中handler就是一个形参为int,返回值为空的函数指针。再看signal函数,通过其原型(即void ( *signal(int signum, void (*handler)(int)) ) (int))可知signal是一个指针函数,即返回值为 指针的函数,那么这样sighandler_t signal(int signum, sighandler_t handler)就好理解了,就是signal的返回值是指针(这里是函数指针),其类型是sighandler_t(即形参为int,返回值为空的函数指针),这里要注意的是sighandler_t是signal返回值的类型,而不是signal的类型,但是是handler的类型。
参数1:信号名;参数2:信号处理函数,当信号发生时调用此函数;
成功返回处理函数的指针,否则返回SIG_ERR;
2.int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact); //检测或修改以及指定信号相关联的处理动作(高级版,可携带消息)
参数1:信号名;参数2:结构体指针(包含信号处理函数相关内容);参数3:结构体指针(用来备份);
成功返回0,否则返回-1;
信号处理发送函数:
3.int kill(pid_t pid, int sig); //将信号发送给进程或者进程组(入门版)
参数1:进程PID;参数2:信号名;
成功返回0,否则返回-1;
4.int sigqueue(pid_t pid, int sig, const union sigval value); //将信号发送给进程或者进组(高级版,可携带信息)
参数1:进程PID;参数2:信号名;参数3:要发送的消息内容;
成功返回0,否则返回-1;
一般signal函数搭配kill函数来使用:
signal.c:
kill.c:
一般sigaction函数搭配sigqueue函数使用:
sigaction.c:
sigqueue.c:
sigqueue.c运行结果:
sigaction.c运行结果:
六、信号量信号量本质上来说不属于进程间通信的方式之一,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据;
最简单的信号量只能取0和1变量,称为二值变量;可以取多个正整数的信号量称为通用信号量;
函数原型:
1.int semget(key_t key, int nsems, int semflg); //创建或获取一个信号量组;
其中nsems为信号量的个数,必须指定;若为现有的信号量集则为0;
成功返回信号量集ID,否则返回-1;
2.int semop(int semid, struct sembuf *sops, unsigned nsops); //对信号量组进行操作,改变信号量的值;
参数1:信号量集ID;参数2:结构体指针,包含信号量相关信息;参数3:信号量数组;
成功返回0,否则返回-1;
3.int semctl(int semid, int semnum, int cmd, ...); //控制信号两个的相关信息;
参数1:信号量集ID;参数2:信号量编号;参数3;信号量的信息命令;参数4:与参数3有关;
成功返回的值与cmd有关,否则返回-1;
特点:1.信号量用于进程间同步,一般配合共享内存使用;2.信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作;3.每次对信号量的PV操作不仅限于信号量值+1或-1,而且可以加减任意数;4.支持信号量组;
这个代码就通过信号量来让子进程先运行,子进程先放信号量,父进程等待信号量,一般不这样用,因为要父进程等待子进程用wait函数即可,信号量一般是搭配共享内存使用的。
总结1.无名管道:速度慢,容量有限,只有亲缘进程之间才能通信;
2.有名管道:速度慢,但是任何进程间都能通信;
3.消息队列:容量受系统限制,第一次读时,要考虑上次没有读完的数据问题;
4.共享内存:能够容易控制容量,速度快,但要考虑同步问题;
5.信号量:用来同步消息;
以上就是进程间通信相关内容,有不对的地方欢迎大家批评指正。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧