三、进程间通信一
来源:互联网 发布:中国商业数据网 编辑:程序博客网 时间:2024/04/29 07:49
一、进程间通讯概述
1、原因:为什么进程间需要通讯
a.数据传输:一个进程需要将它的数据发送给另一个进程。
b.资源共享:多个进程之间共享同样的资源。
c.通知事件:一个进程需要向另一个或者一组进程发送消息,通知它们发生了某事件。主要是在进程同步时,A进程完了需要向B进程发送消息,告知自己结束了。
d.进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另外一个进程的所有操作,并能够及时指导它的状态改变。
2、现在linux使用的进程间通信方式包括:
a.[无名]管道(pipe)和有名管道(FIFO)
b.信号(signal)
c.消息队列
d.共享内存
e.信号量
f.套接字(socket)
二、管道通讯
1、管道通信
什么是管道:管道是单向的,先进先出的,它把进程的输出和另一个进程的进程的输入连接在一起。一个进程(写进程)在管道的尾部写入数据,另一个进程(读进程)从管道的头部读出数据。
2、管道创建
管道包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者用于运行于同一系统的任意两个进程间的通信。
无名管道有pipe()函数创建:
int pipe(int filedis[2]); 当一个管道建立时,它会创建两个文件描述符,并由参数filedis数组返回: filedis[0]用于读管道,filedis[1]用于写管道。成功时,函数返回值为0,否则返回-1。
3、(无名)管道读写
管道用于不同进程间通信。通常先创建一个管道,再通过fork函数创建一个子进程,该子进程会继承父进程所创建的管道。
注意::必须在系统调用fork()前调用pipe(),否则子进程讲不会继承文件描述符。如果是fork先执行,那由于子进程会共享父进程的程序,所以也会创建一个管道,此时,子进程和父进程各自运行自己的管道,无法达到通信的目的。
4、命名管道(FIFO)-创建
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char* pathname,mode_t mode)
pathname:FIFO文件名
mode:属性(见文件操作章节) 一旦创建了一个FIFO,就可用open打开它,一般的文件访问函数(close、read、write等)都可用于FIFO。
5、命名管道-操作
当打开FIFO时,非阻塞标志(O_NONBLOCK)将对以后的读写产生如下影响:
a.没有使用O_NONBLOCK:访问要求无法满足时进程将阻塞。如试图读取空的FIFO,将导致进程阻塞。
b.使用O_NONBLOCK:访问要求无法满足时不阻塞,立刻出错返回,errno是ENXIO.
注意::读写管道时,当数据被从管道中读走之后,数据就不存在于管道中了。
三、信号通讯
1、产生信号的条件:
a.用户按下某些按键时
b.硬件异常产生信号
c.进程用kill函数将信号发送给另一个进程
d.用户可用kill命令讲信号发送给其他进程。
2、信号类型(常见)
SIGHUP:从终端上发出的结束信号
SIGINT:来自键盘的中断信号(Ctrl-c)
SIGKILL:该信号结束接收信号的进程
SIGTERM:kill命令发出的信号
SIGCHLD:标识进程停止或者结束信号
SIGSTOP:来自键盘(Ctrl-Z)或者调试程序的停止执行信号
3、信号处理
1)、忽略此信号:大多数信号都是按照这种方式进行处理的,但是有两种信号却决不能被忽略。它们是:SIGKILL和SIGSTOP.这两种信号不能忽略的原因是:它们向超级用户提供一种终止或停止进程的方法。
2)、执行用户希望的动作:通知内核在某种信号发生时,调用一个用户函数。在用户函数中,执行用户希望的动作。
3)、执行系统默认动作:对大多数信号系统默认动作是终止该进程。
4、信号发送
1)、发送信号的主要函数有kill和raise。主要区别:kill既可以向自身发送信号,也可以向其他进程发送信号。与kill函数不同的是,raise函数是向进程自身发送信号。
#include <sysy/types.h>
#include <signal.h>
int kill(pid_t pid,int signo) pid:进程的ID号,signo:要发送的信号。
int raise(int signo)
kill的pid参数的四种情况:
pid>0:将信号发送给进程ID为pid的进程
pid==0:将信号发送给同组的进程
pid<0:将信号发送给其进程组ID等于pid绝对值的进程
pid==-1:将信号发送给所有进程。
2)、Alarm:使用alarm函数可以设置一个时间值(闹钟时间),当所设置的时间到了时,产生SIGALRM信号。如不捕捉此信号,则默认动作是终止进程。
#include <unistd.h>
unsigned int alarm(unsigned int seconds)
seconds:经过了指定的seconds秒后会产生信号SIGALRM。
3)、Pause:pause函数使调用进程挂起直至捕捉到一个信号。
#include <unistd.h>
int pause(void)
只有执行了一个信号处理函数后,挂起才结束。
5、信号的处理
主要有两种方式:一种是使用简单的signal函数,另一种是使用信号集函数组。
signal函数
#include <signal.h>
void(*signal(int signo,void(*func)(int)))(int)
可理解为signal(int signo,func) func(int) func函数里面就是当实现signo信号时(signo是要想实现的信号类型),函数要做的动作
func可能的值是:
a.SIG_IGN:忽略此信号
b.SIG_DFL:按系统默认方式处理
c.信号处理函数名:使用该函数处理(此函数被称为“捕捉信号函数”)signal函数是信号的接收器,那么kill函数就是信号的发送器int kill(pid_t pid,int signo)
//在终端下输入信号的方法:使用kill命令,kill -s 信号类型 PID
四、共享内存
共享内存是被多个进程共享的一部分物理内存。共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入数据,共享这个内存区域的所有进程就可以立刻看到其中的内容。
1、共享内存实现分为两个步骤:
a.创建共享内存,使用shmget函数
b.映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat数。
2、创建
int shmget(key_t key,int size,int shmflg)
key标识共享内存的键值:0/IPC_PRIVATE.当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中又设置IPC_PRIVATE这个标志,则同样会创建一块新的共享内存。
返回值:如果成功,返回共享内存标识符;如果失败,返回-1.
3、映射
int shmat(int shmid,char *shmaddr,int flag)
参数:shmid:shmget函数返回的共享存储标识符
flag:决定以什么方式来确定映射的地址(通常为0)
shmaddr:自己设定的映射地址,一般设为0,此时系统会自动为我们分配地址,并且返回值会返回这个地址。
返回值:成功则返回共享内存映射到进程中的地址,失败返回-1.
4、释放
int shmdt(char *shmaddr)
当一个进程不再需要共享内存时,需要把它从进程地址空间中脱离。
- 三、进程间通信一
- 进程间通信(一)
- 进程间通信(一)
- C++ 进程间通信一
- 进程间通信(一)
- 进程间通信(一)
- 进程间通信(一)
- Linux环境进程间通信(三)
- Linux环境进程间通信(三)
- Linux环境进程间通信(三)
- Linux环境进程间通信(三)
- Linux环境进程间通信(三)
- Linux环境进程间通信(三)
- Linux环境进程间通信(三)
- Linux环境进程间通信(三)
- Windows 进程间通信(三)
- Linux环境进程间通信(三)
- Linux环境进程间通信(三)
- RMAN 验证 数据文件 和 备份 的有效性
- WorkflowRuntime解析(1)
- 一、文件编程
- Struts2 获取contextPath
- 二、进程控制
- 三、进程间通信一
- 四、进程间通信二
- 五、多线程
- commons-fileupload 上传文件乱码问题
- 《Microsoft SQL Server 2008 Analysis Services Step by Step》学习笔记十二:从Analysis Services检索数据
- DirectX中文文档系列:二、Direct3D设备(device)
- 又一种设计思路
- 组件定义
- 关于分布式系统架构模块通讯方式选择的问题