目录
5、信号量不能传递数据,一般和共享内存配合使用,实现共享内存同步
2、进程间通信方式
UNIX平台进程通信方式
早期进程间通信方式
AT&T的贝尔实验室,对Unix早期的进程间通信进行了改进和扩充,形成了“systemV IPC“,其通信进程主要局限在单个计算机内。
BSD(加州大学伯克利分校的伯克利软件发布中心),跳过了该限制,形成了基于套接字(sockeet)的进程间通信机制。
Linux继承了上述所有的通信方式
3、传统的unix通信方式
3.1 无名管道
3.1.1 无名管道的特点:
1.只能用于具有亲缘关系(父子进程/兄弟进程)的进程之间的通信,速度慢,容量有限
2.半双工的通信方式,具有固定的读端fd[0]和写端fd[1]
3.管道可以看成一种特殊的文件,对于它的读写我们实用文件IO中read和write
3.1.2 创建管道
#include<unistd.h>
int pipe(int fd[2])
参数 fd:包含两个元素的整型数组
返回值 成功:0 出错:-1
管道是基于文件描述符的通信方式。当一个管道建立时,它会创建两个文件描述符fd[0]和fd[1]。其中fd[0]固定用于读管道,而fd[1]固定用于写管道。
构成了一个半双工的通道。
3.1.3 测试管道大小
3.1.4 父子进程间的通信
3.1.5 无名管道需要注意的问题
3.2 有名管道
3.2.1 有名管道的特点
1.有名管道时对无名管道的改进,它可以使互不相关的两个进程互相通信,并且再文件系统中可见,可以通过文件名来找到。
2.半双工的通信方式,进程通过文件IO来操作有名管道。
3.有名管道遵循先进先出原则,不支持lseek()
3.2.2 创建管道
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
int mkfifo(const char *filename,mode_t mode);
参数 filename:要创建的管道
mode:指定创建的管道的访问权限,一般用8进制数表示
返回值 成功:0 出错:-1
3.3 信号
3.3.1 信号的特点:
信号是以一种异步通信方式
3.3.2 信号产生的方式
3.3.2.1 硬件产生信号
ctrl+z SIGTSTP
该信号用于交互停止进程,用户在输入SUSP字符时发出这个信号
ctrl+c SIGINT
该信号在用户输入INTR字符时发出,终端驱动程序发送此信号并送到前台进程中的每一个进程
ctrl+\ SIGQUIT
该信号和SIGINT类似,但由QUIT字符来控制
3.3.2.2 内核发送信号
alarm()
alarm()也称为闹钟函数,它可以在进程中设置一个定时器。当定时器指定的时间到了时,它就向进程发送SIGALRM信号。要注意的是,一个进程只能有一个闹钟时间,如果在调用alarm()之前已设置过闹钟时间,则任何以前的闹钟时间都被新值所代替。
#include<unistd.h>
unsigned int alarm(unsigned int seconds);
seconds:指定秒数,系统经过seconds秒之后向该进程发送SIGALRM信号
返回值:
成功 如果调用此alarm()前,进程中已经设置了闹钟时间,则返回上一个闹钟剩余的时间,否则返回0
出错 -1
pause()
pause()函数是用于将调用进程挂起直至收到信号为止。
#include<unistd.h>
int pause(void);
返回值:-1,并且把errno值设为EINTR
3.3.2.3 软件方式产生信号
kill()
可以发送信号给进程或进程组。注意:它不仅可以终止进程(SIGTERM信号),也可以向进程发送其他信号。
#include<signal.h>
#include<sys.types.h>
int kill(pid_t pid,int sig);
参数 pid:正数:要接收信号的进程的进程号
0:信号被发送到所有和pid进程在同一个进程组的进程
-1:信号发给所有的进程表中的进程(除了进程号最大的进程外)
sig:信号
返回值 成功:0 出错:-1
raise()
与kill()不同,只允许进程向自身发送信号
#include<signal.h>
#include<sys/types.h>
int raise(int sig);
参数 sig:信号
返回值 成功:0 出错:-1
3.3.3 捕获信号
#include<signal.h>
typedef void(*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
参数 signum:指定信号
handler:SIG_IGN:忽略该信号
SIG_DFL:采用系统默认方式处理信号
自定义的信号处理函数指针
返回值 成功:设置之前的信号处理方式
出错:-1
1.执行默认操作
2.忽略信号,即对信号不做任何处理,有两个信号不能忽略 SIGKILL SIGSTOP
3.安装信号,获得信号之后,我们要去执行自定义函数
4、systemV进程间通信方式
4.1 systemV IPC基础
systemV提供的IPC机制主要有消息队列,信号量和共享内存3种机制,和文件一样,IPC在使用前必须先创建,每种IPC都有特定的生产者、所有者和访问权限,使用ipcs命令可以查看当前系统正在使用的IPC工具。
由此可以看出一个IPC工具至少包含key值、ID值、拥有者、权限和使用大小等信息,如果需要手工删除某个IPC机制,可以使用ipcrm命令。
4.2 key值和ID值
Linux系统为每个IPC机制都分配了唯一的ID值,所有针对该IPC机制的操作都使用该ID值。因此,通信的双方都需要通过某个办法来获得ID值。为解决这一问题,IPC在实现时约定使用key值作为参数创建,如果在创建时使用相同的key值将得到同一个IPC对象的ID值,这样就保证了双方可以获取用于传递数据的IPC机制和ID值。key值为一个32位的整型数据。
4.2.1如何获得key值
Linux提供函数ftok()来创建key值
#include<sys/types.h>
#include<sys/ipc.h>
key_t ftok(cinst char *pathname,int proj_id);
参数1 文件路径名,一般情况下使用当前路径
参数2 一个整数,随机值
4.3 消息队列
4.3.1 特点
1.消息队列由
4.3.2相关函数
4.3.2.1创建消息队列
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/msg.h>
int msgget(key_t key,int msgflg);
参数1 ftok()获得key值,key值相,ID值一定一致 IPC_PRIVATE表示新建一个消息队列
参数2 权限 IPC_CREAT|0777 表示消息队列不存在,则新建,存在则返回
IPC_EXCL 表示消息队列存在则出错
4.3.2.2删除消息队列
4.3.2.3发送和接收消息队列
4.4共享内存
4.4.1特点
1.共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝
2.由于多进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等
4.4.2相关函数
1.创建共享内存
2.映射共享内存
即把指定的共享内存映射到进程的地址空间用于访问
3.向共享内存写入数据
4.撤销映射
5.删除共享内存
5、信号量不能传递数据,一般和共享内存配合使用,实现共享内存同步
无名信号量
sem_t sem1 信号量是共享的
sem_init() 初始化信号量
sem_wait() P操作 sem>0 -1操作
sem_post()
有名信号量
sem_wait (P操作)
Sem_post(V操作)