IPC学习
课下作业-IPC
要求:
研究Linux下IPC机制:原理,优缺点,每种机制至少给一个示例,提交研究博客的链接
共享内存
管道
FIFO
信号
消息队列
共享内存
- 共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。
- Linux的2.2.x内核支持多种共享内存方式,如mmap()系统调用,Posix共享内存,以及系统V共享内存。linux发行版本如Redhat 8.0支持mmap()系统调用及系统V共享内存,但还没实现Posix共享内存,本文将主要介绍mmap()系统调用及系统V共享内存API的原理及应用。
实例:
#include<stdio.h>
#include<unistd.h>
int main()
{
int fd[2]; // 两个文件描述符
pid_t pid;
char buff[20];
if(pipe(fd) < 0) // 创建管道
printf("Create Pipe Error!\n");
if((pid = fork()) < 0) // 创建子进程
printf("Fork Error!\n");
else if(pid > 0) // 父进程
{
close(fd[0]); // 关闭读端
write(fd[1], "hello world\n", 12);
}
else
{
close(fd[1]); // 关闭写端
read(fd[0], buff, 20);
printf("%s", buff);
}
return 0;
}
管道
- 管道是Linux支持的最初Unix IPC形式之一,具有以下特点:
- 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
- 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
- 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
- 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
实例:
static int pfd1[2], pfd2[2];
void TELL_WAIT(void)
{
if (pipe(pfd1) < 0 || pipe(pfd2) < 0)
printf("pipe error\n");
}
void TELL_PARENT(pid_t pid)
{
if (write(pfd2[1], "c", 1) != 1)
printf("write error\n");
}
void WAIT_PARENT(void)
{
char c;
if (read(pfd1[0], &c, 1) != 1)
printf("read error\n");
if (c != 'p')
{
printf("WAIT_PARENT: incorrect data\n");
return ;
}
}
void TELL_CHILD(pid_t pid)
{
if (write(pfd1[1], "p", 1) != 1)
printf("write error\n");
}
void WAIT_CHILD(void)
{
char c;
if (read(pfd2[0], &c, 1) != 1)
printf("read error\n");
if (c != 'c')
{
printf("WAIT_CHILD: incorrect data\n");
return ;
}
}
FIFO
- FIFO有时被称为命名管道,未命名的管道只能在两个相关的进程之间使用,而且这两个相关的进程还要有一个共同的祖先进程。但是,通过FIFO,不相关的进程之间也能交换数据。
- FIFP的创建:
#include <sys/stat.h>
int mkfifo(const char* path, mode_t mode);
int mkfifoat(int fd, const char* path, mode_t mode);
实例:
ser.c:
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINE 1024
#define FIFO1 "/tmp/fifo.1"
#define FIFO2 "/tmp/fifo.2"
void Perror(const char *s)
{
perror(s);
exit(EXIT_FAILURE);
}
void server(int readfd, int writefd)
{
/* send msg */
int i = 0;
for (i; i<3; i++) {
char buff[MAXLINE] = {0};
sprintf(buff, "hello world %d", i);
int n = write(writefd, buff, strlen(buff));
sleep(1);
}
char buff[MAXLINE] = {0};
int n = read(readfd, buff, MAXLINE);
if (n > 0) {
printf("read from client:%s\n", buff);
}
}
int main()
{
int readfd, writefd;
/* create two FIFO; OK if they already exist */
if ((mkfifo(FIFO1, 0777) < 0) && (errno != EEXIST))
Perror("can't create FIFO1");
if ((mkfifo(FIFO2, 0777) < 0) && (errno != EEXIST)) {
unlink(FIFO1); /* rm FIFO1 */
Perror("can't create FIFO2");
}
printf("create fifo success\n");
/* 要注意open的顺序 */
readfd = open(FIFO2, O_RDONLY, 0);
writefd = open(FIFO1, O_WRONLY, 0);
printf("open fifo success\n");
/* 让FIFO在进程结束后自动删除 */
unlink(FIFO1);
unlink(FIFO2);
server(readfd, writefd);
return 0;
}
cli.c:
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINE 1024
#define FIFO1 "/tmp/fifo.1"
#define FIFO2 "/tmp/fifo.2"
void Perror(const char *s)
{
perror(s);
exit(EXIT_FAILURE);
}
void client(int readfd, int writefd)
{
/* read msg */
int i = 0;
for (i; i<3; i++) {
char buff[MAXLINE] = {0};
int n = read(readfd, buff, MAXLINE);
if (n > 0) {
printf("read from server:%s\n", buff);
}
}
char *buff = "goodby server";
write(writefd, buff, strlen(buff));
}
int main()
{
int readfd, writefd;
/* create two FIFO; OK if they already exist */
if ((mkfifo(FIFO1, 0777) < 0) && (errno != EEXIST))
Perror("can't create FIFO1");
if ((mkfifo(FIFO2, 0777) < 0) && (errno != EEXIST)) {
unlink(FIFO1); /* rm FIFO1 */
Perror("can't create FIFO2");
}
/* 要注意open的顺序 */
writefd = open(FIFO2, O_WRONLY);
readfd = open(FIFO1, O_RDONLY);
client(readfd, writefd);
return 0;
}
信号
- 信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
- 信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。
实例:
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
void new_op(int,siginfo_t*,void*);
int main(int argc,char**argv)
{
struct sigaction act;
int sig;
sig=atoi(argv[1]);
sigemptyset(&act.sa_mask);
act.sa_flags=SA_SIGINFO;
act.sa_sigaction=new_op;
if(sigaction(sig,&act,NULL) < 0)
{
printf("install sigal error\n");
}
while(1)
{
sleep(2);
printf("wait for the signal\n");
}
}
void new_op(int signum,siginfo_t *info,void *myact)
{
printf("receive signal %d", signum);
sleep(5);
}
消息队列
- 消息队列是消息的链表,存放在内核中并由消息队列标识符标识。在某个进程往一个队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达。这跟管道和FIFO是相反的,对后两者来说,除非读出者已存在,否则先有写入者是没有意义的。
实例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h> //包含ftok
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#define MSG_W 0200
#define BUF_SIZE 512
typedef struct msgbuf
{
long mtype ;
char mdata[BUF_SIZE] ;
} mymsg_t ;
int
main(int argc, char** argv)
{
int mqid ; //消息队列的描述符
size_t msglen ; //消息的长度
long msgtype ; //消息的类型
mymsg_t* ptr ; //消息结构的指针
//用户未按格式输入
if (argc != 3)
puts("usage: send <pathname> <type>") ;
msgtype = atoi(argv[2]) ;
//获取已存在消息队列的描述符
mqid = msgget(ftok(argv[1], 0), MSG_W) ;
//构造一条消息
ptr = calloc(sizeof(long) + msglen, sizeof(char)) ;
ptr->mtype = msgtype ;
snprintf(ptr->mdata, BUF_SIZE, "Hi,Boy~") ;
//发送消息
msglen = strlen(ptr->mdata) ;
msgsnd(mqid, ptr, msglen, 0) ;
exit(0) ;
}
IPC学习的更多相关文章
- Linux进程间通信IPC学习笔记之同步二(SVR4 信号量)
Linux进程间通信IPC学习笔记之同步二(SVR4 信号量)
- Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
- Linux进程间通信IPC学习笔记之消息队列(SVR4)
Linux进程间通信IPC学习笔记之消息队列(SVR4)
- Linux进程间通信IPC学习笔记之有名管道
基础知识: 有名管道,FIFO先进先出,它是一个单向(半双工)的数据流,不同于管道的是:是最初的Unix IPC形式,可追溯到1973年的Unix第3版.使用其应注意两点: 1)有一个与路径名关联的名 ...
- Linux进程间通信IPC学习笔记之管道
基础知识: 管道是最初的Unix IPC形式,可追溯到1973年的Unix第3版.使用其应注意两点: 1)没有名字: 2)用于共同祖先间的进程通信: 3)读写操作用read和write函数 #incl ...
- Linux进程间通信IPC学习笔记
linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...
- Linux进程间通信IPC学习笔记之同步一(线程、互斥锁和条件变量)
基础知识: 测试代码: 参考资料: Posix 多线程程序设计
- Linux进程间通信IPC学习笔记之消息队列(Posix)
基础知识: 消息队列可认为是一个消息链表,有足够写权限的线程可往队列中放置消息,有足够读权限的线程可以从队列中取走消息.在某个进程往一人队列写入消息之前,并不需要另外某个进程在该队列上等待消息的到达. ...
- 20155326 第十周课下作业-IPC
20155326 第十周课下作业-IPC 学习题目: 研究Linux下IPC机制:原理,优缺点,每种机制至少给一个示例,提交研究博客的链接 共享内存 管道 FIFO 信号 消息队列 学习过程 -IPC ...
随机推荐
- 1.创建maven 项目 动态web工程完整示例
注意,以下所有需要建立在你的eclipse等已经集成配置好了maven了,说白了就是新建项目的时候已经可以找到maven了 没有的话需要安装maven 一.创建项目 1.新建maven项目,如果不在上 ...
- 在Windows2003下如何查看IIS站点中对应的PID值
分享:查看IIS站点中对应的PID值 在Win2003下,提供了一个命令,可以方便的查看.cmd -> iisapp -a 显示W3WP.exe PID: 1264 AppPoolID: hxW ...
- selenium模拟鼠标操作
Selenium提供了一个类ActionChains来处理模拟鼠标事件,如单击.双击.拖动等. 基本语法: class ActionChains(object): """ ...
- Sql Server数据库备份脚本以及如何在阿里云云数据库RDS还原数据库(代码源自阿里云)
今天研究阿里云服务数据库的迁移,备份和还原的时候,在阿里云web后台发现了一个很好用的sql脚本,就默默地偷了过来,它可以支持全量备份,差异备份和日志备份,代码解释也都很清楚,我也尝试着跑了一下,性能 ...
- 名词解释:Linux内存管理之RSS和VSZ
Linux内存管理中不管是top命令还是pmap命令,都会有RSS和VSZ这两个名词,这里解释一下: RSS( Resident Set Size )常驻内存集合大小,表示相应进程在RAM中占用了多少 ...
- jsp 页面间传递参数
JSP页面间传递参数是经常需要使用到的功能,有时还需要多个JSP页面间传递参数.下面介绍一下实现的方法. (1)直接在URL请求后添加 如:< a href="thexuan.jsp? ...
- session更换存储,实现在多台服务器共享
场景 web服务器有多台,每台服务器都会存贮自己的session,session无法在多台服务器共享.所以就需要更换session的存贮空间,存贮在一个共用的空间.通常为了读写速度,我们会选择存贮在内 ...
- 洛谷 P2764 最小路径覆盖问题【最大流+拆点+路径输出】
题目链接:https://www.luogu.org/problemnew/show/P2764 题目描述 «问题描述: 给定有向图G=(V,E).设P 是G 的一个简单路(顶点不相交)的集合.如果V ...
- [Violet]天使玩偶/SJY摆棋子
题目 \(KD-tree\)做最近点对的复杂度好像是假的吧,怎么看也看不出来是\(O(\sqrt{n})\)啊 首先\(KD-tree\)长得和平衡树还是很像的,每个节点都存储了一个\(k\)维空间上 ...
- jenkins 调用 k8s api
delete_old_images() { #删除以前的镜像,节省本地空间 if docker images | grep $javaname ; then docker rmi -f `docker ...