一.为什么需要进程通信

1)数据传输

一个进程需要把它的数据发送给另一个进程。

2)资源共享

多个进程之间共享同样的资源。

3)通知事件

一个进程向另外一个进程发送消息,通知它发生了某事件。

4)进程控制

控制运行、停止等。

二.IPC的由来

1)Unix进程通信

2)SystemV进程通信

3)POSIX(Portable Operating System Interface)进程通信

三.进程通信方式分类

1.管道通信(有名、无名管道)

含义:单向,先进先出的。

分类:无名(父子进程)、有名(任意进程)。

int pipe(int filedis[2]);

filedis[0]读管道;

filedis[1]写管道;

close() 关闭文件描述符。

2)//创建方式举例:

#include

#include

#include

#include

int main()

{

int pipe_fd[2];

if(pipe(pipe_fd)<0)

{

printf("pipe create error\n");

return -1;

}

else

printf("pipe create success\n");

close(pipe_fd[0]);

close(pipe_fd[1]);

}

3)//父子进程之间通信举例

注意:必须fork()前调用pipe(),否则子进程无法继承文件描述符。

#include

#include

#include

#include

#include

int main()

{

int pipe_fd[2];

pid_t pid;

char buf_r[100];

char* p_wbuf;

int r_num;

memset(buf_r,0,sizeof(buf_r));

/*创建管道*/

if(pipe(pipe_fd)<0)

{

printf("pipe create error\n");

return -1;

}

/*创建子进程*/

if((pid=fork())==0) //子进程 OR 父进程?

{

printf("\n");

close(pipe_fd[1]);

sleep(2); /*为什么要睡眠*/

if((r_num=read(pipe_fd[0],buf_r,100))>0)

{

printf( "%d numbers read from the pipe is %s\n",r_num,buf_r);

}

close(pipe_fd[0]);

exit(0);

}

else if(pid>0)

{

close(pipe_fd[0]);

if(write(pipe_fd[1],"Hello",5)!=-1)

printf("parent write1 Hello!\n");

if(write(pipe_fd[1]," Pipe",5)!=-1)

printf("parent write2 Pipe!\n");

close(pipe_fd[1]);

sleep(3);

waitpid(pid,NULL,0); /*等待子进程结束*/

exit(0);

}

return 0;

}

//3)有名管道

int mkfifo(const char* pathname, mode_t mode)

//读管道数据

#include

#include

#include

#include

#include

#include

#include

#define FIFO "/tmp/myfifo"

main(int argc,char** argv)

{

char buf_r[100];

int fd;

int nread;

/* 创建管道 */

if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))

printf("cannot create fifoserver\n");

printf("Preparing for reading bytes...\n");

memset(buf_r,0,sizeof(buf_r));

/* 打开管道 */

fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);

if(fd==-1)

{

perror("open");

exit(1);

}

while(1)

{

memset(buf_r,0,sizeof(buf_r));

if((nread=read(fd,buf_r,100))==-1)

{

if(errno==EAGAIN)

printf("no data yet\n");

}

printf("read %s from FIFO\n",buf_r);

sleep(1);

}

pause(); /*暂停,等待信号*/

unlink(FIFO); //删除文件

}

//写管道数据

#include

#include

#include

#include

#include

#include

#include

#define FIFO_SERVER "/tmp/myfifo"

main(int argc,char** argv)

{

int fd;

char w_buf[100];

int nwrite;

/*打开管道*/

fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);

if(argc==1)

{

printf("Please send something\n");

exit(-1);

}

strcpy(w_buf,argv[1]);

/* 向管道写入数据 */

if((nwrite=write(fd,w_buf,100))==-1)

{

if(errno==EAGAIN)

printf("The FIFO has not been read yet.Please try later\n");

}

else

printf("write %s to the FIFO\n",w_buf);

}

2.信号通信(signal)

//2.1信号介绍

1)产生信号:用户按键,除数为0的异常等。

2)kill函数将信号发送给进程。

3)kill命令将信号发送给进程。

格式如下:kill -s SIGQUIT 进程ID

ctrl +z == SIGSTOP

//2.2信号处理

1)忽略新信号,但 SIGKILL和SIGSTOP不能被忽略。

2)执行用户希望的动作。

3)执行系统默认动作。

2.3发送信号常见函数

1)kill

给自己或者其他进程。

2)raise

只能给自己发信号。

3)alarm

产生SIGALRM信号。

如果不捕获此信号,则默认动作是终止该进程。

4)Pause

调用进程挂起直至捕获到一个信号。

2.4信号的处理方式

1)signal

需要的头文件#include

#include

#include

#include

void my_func(int sign_no)

{

if(sign_no==SIGINT)

printf("I have get SIGINT\n");

else if(sign_no==SIGQUIT)

printf("I have get SIGQUIT\n");

}

int main()

{

printf("Waiting for signal SIGINT or SIGQUIT \n ");

/*注册信号处理函数*/

signal(SIGINT, my_func);

signal(SIGQUIT, my_func);

pause();

exit(0);

}

[root@localhost pipe]# ./mysignal

Waiting for signal SIGINT or SIGQUIT

I have get SIGQUIT

3.共享内存

共享内存访问快,是被多个进程共享的一块物理内存。

一个进程向里写入数据,共享内存的其他进程都能收到数据。

3.2实现步骤

1)创建共享内存

int shmget(key_t key, …)

2)映射

int shmat(int shmid, char…)

3)解除映射

int shmdt(char* shmaddr)

3.3举例:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define PERM S_IRUSR|S_IWUSR

/* 共享内存 */

int main(int argc,char **argv)

{

int shmid;

char *p_addr,*c_addr;

if(argc!=2)

{

fprintf(stderr,"Usage:%s\n\a",argv[0]);

exit(1);

}

/* 创建共享内存 */

if((shmid=shmget(IPC_PRIVATE,1024,PERM))==-1)

{

fprintf(stderr,"Create Share Memory Error:%s\n\a",strerror(errno));

exit(1);

}

/* 创建子进程 */

if(fork()) // 父进程写

{

p_addr=shmat(shmid,0,0);

memset(p_addr,'\0',1024);

strncpy(p_addr,argv[1],1024);

wait(NULL); // 释放资源,不关心终止状态

exit(0);

}

else // 子进程读

{

sleep(1); // 暂停1秒

c_addr=shmat(shmid,0,0);

printf("Client get %s\n",c_addr);

exit(0);

}

}

4.消息队列

4.1本质

链表,

4.2常用消息队列

1)POSIX消息队列

2)系统V消息队列

随内核持续的,只有内核重启或者删除,该队列才会删除。

4.3常用接口

键值:每个消息队列都有一个键值。

key_t ftok(char* pathname, char proj)

1)创建&打开

msgget(key_t key, int msgflag)

//IPC_CREATE

//IPC_EXEC

//IPC_NOWAIT 不阻塞

2)发送消息

int msgsend(int msqid, struct msgbuf* msgp, int msgsz, int msgflg)

//向消息队列发送一条消息

struct msgbuf

{

long mtype; //消息类型

char mtext[1]; //消息数据的首地址

};

3)接收消息

int msgrcv(int msqid, struct msgbuf* msgp, int msgsz, long msgtype, int msgflg)

举例:`这里写代struct msg_buf

{

int mtype;

char data[255];

};

int main()

{

key_t key;

int msgid;

int ret;

struct msg_buf msgbuf;

key=ftok("/tmp/2",'a');

printf("key =[%x]\n",key);

msgid=msgget(key,IPC_CREAT|0666); /*通过文件对应*/

if(msgid==-1)

{

printf("create error\n");

return -1;

}

//设置消息类型和数据(编号为pid)

msgbuf.mtype = getpid();

strcpy(msgbuf.data,"test haha");

ret=msgsnd(msgid,&msgbuf,sizeof(msgbuf.data),IPC_NOWAIT);

if(ret==-1)

{

printf("send message err\n");

return -1;

}

memset(&msgbuf,0,sizeof(msgbuf));

ret=msgrcv(msgid,&msgbuf,sizeof(msgbuf.data),getpid(),IPC_NOWAIT);

if(ret==-1)

{

printf("recv message err\n");

return -1;

}

printf("recv msg =[%s]\n",msgbuf.data);

}

5.信号量

5.1主要用途

进程间的互斥和同步,保护临界资源。

5.2分类

1)二值信号量,最大值为1(最多允许一个访问)

2)计数信号量,信号灯的值可以取任意非负值。

5.3操作

1)打开和创建

int semget(key_t key, int nsems, int semflg)

2)操作

int semop(int semid, struct sembuf *sops, unsigned nsops)

6.套接字(socket)

小结:

以上知识点目前没有在Linux项目中使用的较少,但必须要有知识储备,以备不时之需。

linux一个进程通知另外一个进程,Linux进程通信学习笔记相关推荐

  1. php 孤儿进程组,孤儿进程组(Orphaned Process Groups) APUE2学习笔记

    1)先说明孤儿进程(orphan process)的概念: 一个其父进程已终止的进程称为孤儿进程(orphan process),这种进程由 init 进程"收养". 本文中,讨论 ...

  2. linux下串口通信详解,Linux操作系统下的串口通信学习笔记

    http://www.diybl.com/ 2008-7-5 网络 点击: [ 评论 ] - - 文章搜索:     [点击打包该文章] [本站开通在线QQ讨论群] CBAUDEX (不属于POSIX ...

  3. 鸟哥的Linux私房菜(基础版)第五章学习笔记

    第五章 启动关机.在线求助与执行命令的方式 学习笔记 首次登入FC图形界面 KDE的简单操作 切换X Window与命令行模式 用命令行登入Linux 在命令行模式执行命令 基础命令操作 重要的热键 ...

  4. 进程通信学习笔记(读写锁)

    读写锁的分配规则: 1.只要没有线程持有某个给定的读写锁用于写,那么任意数目的线程可以持有读写锁用于读 2.仅当没有线程持有某个给定的读写锁用于读或用于写时,才能分配该读写锁用于写 这种对于某个给定资 ...

  5. 进程通信学习笔记(System V消息队列)

    跟Posix消息队列一样,不存在这样的要求:某个进程往一个队列中写入一个消息,另外一个进程下在等待该队列上一个消息的到达 系统中的消息队列,定义在<sys/msg.h>头文件中的信息结构: ...

  6. 进程通信学习笔记(管道)

    1.管道 pipe函数创建单向数据流 #include <unistd.h> int pipe(int fd[2]); 成功返回0,失败返回-1 该函数返回两个文件描述字:fd[0]和fd ...

  7. Linux三剑客:grep、sed、awk基础入门学习笔记

    今天分享的学习笔记内容是Linux三剑客,包括grep.sed.awk命令的基础知识,以及一些正则表达式相关内容. 正则表达式是对字符串和特殊字符操作的一种逻辑公式,就是用事先定义好的一些特定字符及这 ...

  8. mysql循环查询一个表中的数据并进行修改_JavaScript学习笔记(二十四)-- MYSQL基础操作...

    MYSQL mysql 是一个数据库的名字 和 php 合作的比较好的数据库 之前我们说过一个问题,前端向后端索要数据,后端就是去数据库中查询数据,返回给前端 接下来就聊聊使用 php 操作数据库 M ...

  9. linux中20个高级命令 8月26日学习笔记

    linux中20个高级命令 文章目录 linux中20个高级命令 1.ifconfig命令 1.1 检查所有网络接口 1.2 禁用网卡 1.3 启用网卡 1.4为网卡分配 IP 地址 1.5 更改网卡 ...

最新文章

  1. yolo-mask的损失函数l包含三部分_【AI初识境】深度学习中常用的损失函数有哪些?...
  2. mysqlimport命令
  3. C++ 对象的内 存布局(下)
  4. 《Adobe InDesign CS6中文版经典教程》—第1课1.5节修改文档的缩放比例
  5. R学习之——R用于文本挖掘(tm包)
  6. python从excel中读取数据
  7. windows模拟微信小程序_Windows 版微信新版本内测!小程序可以直接添加到电脑桌面了...
  8. 华为的接班人要具备哪些能力?任正非这样说...
  9. Python封装的获取文件目录的函数
  10. 客户端无法远程连接服务器的问题
  11. 删除Navicat注册表
  12. 使用BootStrap制作网页页面
  13. 跨交换机实现VLAN实验
  14. vue校验输入框不能有中文
  15. 卡方检验值转换为P值
  16. (原创)android6.0系统 PowerManager深入分析
  17. 合唱队形(模板,排序问题)
  18. Linux网络配置(NAT)
  19. 利用arcgispro将倾斜摄影三维数据OSGB转换为slpk格式
  20. 汽车之家数据 下载合集

热门文章

  1. numpy中矩阵运算的特点
  2. 航天智慧物流创意组-技术培训二期
  3. 更新不了_一个作者在起点中文网写小说,半年更新38万字,还是没签约成功
  4. windows环境下python怎么安装mlxtend-python连接QQ实现自动回复python 机器学习库
  5. 静态移值编译的关键环境变量
  6. ajax如何请求json文件,简单的ajax请求加载外部json文件
  7. html5动态气泡效果6,[jQuery]Canvas气泡动态背景效果
  8. idea 报系统分区磁盘不足_系统磁盘管理功能讲解,电脑硬盘分区格式化修改驱动器号图文教程...
  9. python中rand和randn_rand、randn、randi区别及用法
  10. matlab 句柄图像尝试