进程间的通信机制
2015-11-07 22:19
274 查看
IPC,进程间通信
1)文件
2)信号
3)管道
4)共享内存
5)消息队列
6)信号量
7)socket
1 管道
1.1 有名管道
1)命令行方式
mkfifo fifo
2)编程模型
A进程 B进程 相关函数
-----------------------------------------------------------------
创建管道 mkfifo()
-----------------------------------------------------------------
写打开管道 读打开文件 open()
-----------------------------------------------------------------
写入数据 读出数据 write/read
-----------------------------------------------------------------
关闭管道 关闭管道 close
-----------------------------------------------------------------
删除管道 unlink
----------------------------------------------------------------
1.2 无名管道(适用于父子进程之间的通信)
涉及到的API函数,pipe()
#include <unistd.h>
int pipe(int pipefd[2])
作用:创建管道文件
以只读方式打开管道文件,将文件描述符保存到pipefd[0]
以只写方式打开管道文件安,将文件描述符保存到pipefd[1]
编程步骤:
1)调用pipe函数,在内核中创建管道文件,并通过输出参数pipefd[0]获得读或者写管道的文件描述符
2)调用fork函数,创建子进程
3)写数据的进程,关闭读端,close(pipefd[0])
4)度数据的进程,关闭写端,close(pipefd1[1])
5)父子进程分别关闭自己的文件描述符
编程:一端写入20个数据,另一端读出这20个数据
pipe.c
1.3 管道特点
通常使用的管道都是半双工的
2 共享内存 消息队列 信号量集
以上三种IPC被称作 XSI IPC,编程具有很大的共性
1)标识符(身份) 和键(身份证编号)
2)键值如何确定?(身份证的编码方式)
a)使用宏IPC_PRIVATE作为KEY:一般用于父子进程之间
b)可以使用ftok()函数来创建key(重点)
c)在公共头文件中定义每个使用的key给一个固定值
key本质上就是一个整数
3)服务器进程用此键值来创建IPC对象
xxxget():shmget() /msgget()/ semget()
客户机进程用此键值来获取该IPC对像
4)服务器进程和客户机进程之间就可以交换信息了
系统提供的函数:
共享内存:shmat()
消息队列:msgsnd() msgrecv()
信号量集:semop()
5)获取IPC对象的属性信息
xxxctl:shmctl()/ msgctl()/ semctl()
6)销毁创建的IPC对象
xxxctl:shmctl()/ msgctl()/ semctl()
3 共享内存
内核管理一篇物理内存,允许不同进程映射,多个进程可以映射同一块物理内存,映射后的
虚拟地址可能不尽相同,但对应的物理地址相同。
映射物理内存叫挂接,使用后接触映射叫脱节
3.1编程步骤
1)获得key,头文件中定义或者使用:ftok()
#include<sys/types.h>
#include<sys/ipc.h>
key_t ftok(const char *pathname, int proj_id)
psthname:存在并且可访问的路径(文件名)
proj_id:取值范围为1-255
2)使用key来创建或者获取一块共享内存:shmget()
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg)
key:就是ftok()返回值
size:
要申请的共享内存的字节数
建议size为4096的整数倍
若是创建共享内存,必须指定size为非0
若是获取共享内存,size取0即可
shmflg:
IPC_CREAT:创建共享内存
IPC_EXCL:测试key对应
modes:
3)映射共享内存,挂接:shmat()
#include<sys/types.h>
#include<sys/shm.h>
void *shmat(int shmid, const void *shmadd, int shmflg)
shmid:要映射的共享内存段
shmaddr:等价于mmap()函数中的addr,通常区0,由操作系统分配即可
shmflg:
0:以读写方式使用共享内存
SHM_RDONLY:以只读方式使用共享内存
返回值:成功返回虚拟地址的首地址
出错返回-1
4)使用共享内存进行数据交换(C编程)
5)解除映射,脱接:shmdt()
#include<sys/types.h>
#include<sys/shm.h>
int shmdt(sonst void *shmaddr)
返回值:成功0
失败-1
6)如果后续不会再使用该共享内存,销毁该共享内存:shmctl()
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
shmid:
cmd:
IPC_RMID:销毁共享内存
buf:
返回值:成功0
失败-1
errno
3.2 编程
shma.c
shmb.c
编程获取属性字段:
shmctl.c
struct shmid_ds:
练习:shma进程如果没有按下回车,而是ctrl+c,会造成他所创将的共享内存得不到销毁,
如何树立该问题?
处理消息响应函数。
3.3 命令行访问IPC
ipcs:查看系统中现有的共享内存,消息队列,信号量集
-a:查看所有
-m:查看共享内存
-q:查看消息队列
-s:信号量集
ipcrm:删除IPC
-q
-m
-s
-M
-Q
重启:也可以销毁文件
3.4 特点
优点:最快的IPC。
缺点:需要自己编程解决访问共享内存的同步问题
4 消息队列
先把要传递的数据封装到消息中,然后把消息存入队列
消息队列也是采用内存做交互的媒介,系统内核管理一个队列,完成消息的FIFO
4.1 编程步骤
1)创建key
2)使用msgget()来创建/获取消息队列
3)向队列中存入消息msgsnd,取出消息msgrcv()
int msgsnd(msgid,msgp,size,msgflg)
msgid,确定操作那个操作队列
msgp,写入消息队列的数据
size,消息长度
msgflg,0 代表阻塞,写入不成功不反回
IPC_NOWAIT 非阻塞,写入不成功,立即返回错误信息
int msgrcv(msgid, msgp, size, msgtype, msgflg)
msgid:确定要操作那个消息队列
msgp:取到消息放入的缓冲区
size:期望获得消息长度
msgtype:0 取消消息队列中的第一消息,忽略类型
>0 接受特定类型消息中的第一个
<0 接受类型小于等于msgtype绝对值的消息,
msgflg:0代表阻塞,读取不成工不返回
IPC_NOWAIT,非阻塞,不成功立即返回一个错误信息
返回值:成功返回读取到的字节个数
失败返回
4)销毁消息队列msgctl
4.2 正规用法
消息分有类型消息和无类型消息。有类型消息编程规范,接收数据时可以进行细分。
涉及到的消息结构体
struct msgbuf
{
long mtype;//消息类型
buf;//缓冲区
}
5 信号量集
1)一般用于进程间通信
2)信号量的集合(数组)
3)信号量和信号没有任何关系
4)信号量本质是一个计数器(int),负责控制访问共享资源的最大并行进程总数。信号量
5)初始设为最大值。每个进程访问共享资源前计数减一,每个进程结束共享资源访问计数加一。
当计数减为0时阻塞,知道计数重新大于0,解除阻塞。
6)如果有多个共享资源需要分别控制最大并行进程数,就需要多个信号量。把多个信号量放在
一个数组中,这个数组就叫信号量集。
7)编程时,系统提供的接口操作对象是信号量集,而不是单一的信号量。
5.1 编程步骤
1)生成key ftok()
2)创建信号量集 semget()
int semget(key,nsems, flag)
key:获取/创建信号量集的唯一标志
nsems:信号量的个数
flag:IPC_CREAT:
IPE_EXCL:
mode:权限属性
返回值:错误返回-1
成功返回信号量集合的ID
3)设置初始值 semctl()
int semctl(semid, semnum, cmd, ...)
semid:要操作那个信号量
semnum:要操作第几个信号量
cmd:IPC_RMID:删除信号量集合
SETVAL:设置semid信号量集中第semnum个信号量的值为arg.val
union semum
{
int val;
...
}
IPC_STAT:
IPC_SET:
aggument:
4)正常使用,访问共享资源信号量-1
访问结束信号量+1
semop
5)销毁信号量集合
semctl(, IPC_RMID,...)
sema.c
semb.c
int semop(int semid, struct sembuf *sops, unsigned nsops)
semid
sops:
struct sembuf
{
sem_num:信号量的下标
sem_op:操作数
sem_flg:操作的标记
}
该函数对semid指定的信号量集合中,由sops所指向的包含nsops个元素的,依次执行如下操作:
sem_op>0:将sem_op加到sem_num对应的信号量的计数值上去
sem_op<0:将sem_op加到sem_num对应的信号量的计数值上去
sem_op=0:将sem_num对应的信号量计数为0才返回
sem_flg:0:代表阻塞
1:IPC_NOWAIT,非阻塞,不等待,出错返回
nsops:
1)文件
2)信号
3)管道
4)共享内存
5)消息队列
6)信号量
7)socket
1 管道
1.1 有名管道
1)命令行方式
mkfifo fifo
2)编程模型
A进程 B进程 相关函数
-----------------------------------------------------------------
创建管道 mkfifo()
-----------------------------------------------------------------
写打开管道 读打开文件 open()
-----------------------------------------------------------------
写入数据 读出数据 write/read
-----------------------------------------------------------------
关闭管道 关闭管道 close
-----------------------------------------------------------------
删除管道 unlink
----------------------------------------------------------------
1.2 无名管道(适用于父子进程之间的通信)
涉及到的API函数,pipe()
#include <unistd.h>
int pipe(int pipefd[2])
作用:创建管道文件
以只读方式打开管道文件,将文件描述符保存到pipefd[0]
以只写方式打开管道文件安,将文件描述符保存到pipefd[1]
编程步骤:
1)调用pipe函数,在内核中创建管道文件,并通过输出参数pipefd[0]获得读或者写管道的文件描述符
2)调用fork函数,创建子进程
3)写数据的进程,关闭读端,close(pipefd[0])
4)度数据的进程,关闭写端,close(pipefd1[1])
5)父子进程分别关闭自己的文件描述符
编程:一端写入20个数据,另一端读出这20个数据
pipe.c
1.3 管道特点
通常使用的管道都是半双工的
2 共享内存 消息队列 信号量集
以上三种IPC被称作 XSI IPC,编程具有很大的共性
1)标识符(身份) 和键(身份证编号)
2)键值如何确定?(身份证的编码方式)
a)使用宏IPC_PRIVATE作为KEY:一般用于父子进程之间
b)可以使用ftok()函数来创建key(重点)
c)在公共头文件中定义每个使用的key给一个固定值
key本质上就是一个整数
3)服务器进程用此键值来创建IPC对象
xxxget():shmget() /msgget()/ semget()
客户机进程用此键值来获取该IPC对像
4)服务器进程和客户机进程之间就可以交换信息了
系统提供的函数:
共享内存:shmat()
消息队列:msgsnd() msgrecv()
信号量集:semop()
5)获取IPC对象的属性信息
xxxctl:shmctl()/ msgctl()/ semctl()
6)销毁创建的IPC对象
xxxctl:shmctl()/ msgctl()/ semctl()
3 共享内存
内核管理一篇物理内存,允许不同进程映射,多个进程可以映射同一块物理内存,映射后的
虚拟地址可能不尽相同,但对应的物理地址相同。
映射物理内存叫挂接,使用后接触映射叫脱节
3.1编程步骤
1)获得key,头文件中定义或者使用:ftok()
#include<sys/types.h>
#include<sys/ipc.h>
key_t ftok(const char *pathname, int proj_id)
psthname:存在并且可访问的路径(文件名)
proj_id:取值范围为1-255
2)使用key来创建或者获取一块共享内存:shmget()
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg)
key:就是ftok()返回值
size:
要申请的共享内存的字节数
建议size为4096的整数倍
若是创建共享内存,必须指定size为非0
若是获取共享内存,size取0即可
shmflg:
IPC_CREAT:创建共享内存
IPC_EXCL:测试key对应
modes:
3)映射共享内存,挂接:shmat()
#include<sys/types.h>
#include<sys/shm.h>
void *shmat(int shmid, const void *shmadd, int shmflg)
shmid:要映射的共享内存段
shmaddr:等价于mmap()函数中的addr,通常区0,由操作系统分配即可
shmflg:
0:以读写方式使用共享内存
SHM_RDONLY:以只读方式使用共享内存
返回值:成功返回虚拟地址的首地址
出错返回-1
4)使用共享内存进行数据交换(C编程)
5)解除映射,脱接:shmdt()
#include<sys/types.h>
#include<sys/shm.h>
int shmdt(sonst void *shmaddr)
返回值:成功0
失败-1
6)如果后续不会再使用该共享内存,销毁该共享内存:shmctl()
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
shmid:
cmd:
IPC_RMID:销毁共享内存
buf:
返回值:成功0
失败-1
errno
3.2 编程
shma.c
shmb.c
编程获取属性字段:
shmctl.c
struct shmid_ds:
练习:shma进程如果没有按下回车,而是ctrl+c,会造成他所创将的共享内存得不到销毁,
如何树立该问题?
处理消息响应函数。
3.3 命令行访问IPC
ipcs:查看系统中现有的共享内存,消息队列,信号量集
-a:查看所有
-m:查看共享内存
-q:查看消息队列
-s:信号量集
ipcrm:删除IPC
-q
-m
-s
-M
-Q
重启:也可以销毁文件
3.4 特点
优点:最快的IPC。
缺点:需要自己编程解决访问共享内存的同步问题
4 消息队列
先把要传递的数据封装到消息中,然后把消息存入队列
消息队列也是采用内存做交互的媒介,系统内核管理一个队列,完成消息的FIFO
4.1 编程步骤
1)创建key
2)使用msgget()来创建/获取消息队列
3)向队列中存入消息msgsnd,取出消息msgrcv()
int msgsnd(msgid,msgp,size,msgflg)
msgid,确定操作那个操作队列
msgp,写入消息队列的数据
size,消息长度
msgflg,0 代表阻塞,写入不成功不反回
IPC_NOWAIT 非阻塞,写入不成功,立即返回错误信息
int msgrcv(msgid, msgp, size, msgtype, msgflg)
msgid:确定要操作那个消息队列
msgp:取到消息放入的缓冲区
size:期望获得消息长度
msgtype:0 取消消息队列中的第一消息,忽略类型
>0 接受特定类型消息中的第一个
<0 接受类型小于等于msgtype绝对值的消息,
msgflg:0代表阻塞,读取不成工不返回
IPC_NOWAIT,非阻塞,不成功立即返回一个错误信息
返回值:成功返回读取到的字节个数
失败返回
4)销毁消息队列msgctl
4.2 正规用法
消息分有类型消息和无类型消息。有类型消息编程规范,接收数据时可以进行细分。
涉及到的消息结构体
struct msgbuf
{
long mtype;//消息类型
buf;//缓冲区
}
5 信号量集
1)一般用于进程间通信
2)信号量的集合(数组)
3)信号量和信号没有任何关系
4)信号量本质是一个计数器(int),负责控制访问共享资源的最大并行进程总数。信号量
5)初始设为最大值。每个进程访问共享资源前计数减一,每个进程结束共享资源访问计数加一。
当计数减为0时阻塞,知道计数重新大于0,解除阻塞。
6)如果有多个共享资源需要分别控制最大并行进程数,就需要多个信号量。把多个信号量放在
一个数组中,这个数组就叫信号量集。
7)编程时,系统提供的接口操作对象是信号量集,而不是单一的信号量。
5.1 编程步骤
1)生成key ftok()
2)创建信号量集 semget()
int semget(key,nsems, flag)
key:获取/创建信号量集的唯一标志
nsems:信号量的个数
flag:IPC_CREAT:
IPE_EXCL:
mode:权限属性
返回值:错误返回-1
成功返回信号量集合的ID
3)设置初始值 semctl()
int semctl(semid, semnum, cmd, ...)
semid:要操作那个信号量
semnum:要操作第几个信号量
cmd:IPC_RMID:删除信号量集合
SETVAL:设置semid信号量集中第semnum个信号量的值为arg.val
union semum
{
int val;
...
}
IPC_STAT:
IPC_SET:
aggument:
4)正常使用,访问共享资源信号量-1
访问结束信号量+1
semop
5)销毁信号量集合
semctl(, IPC_RMID,...)
sema.c
semb.c
int semop(int semid, struct sembuf *sops, unsigned nsops)
semid
sops:
struct sembuf
{
sem_num:信号量的下标
sem_op:操作数
sem_flg:操作的标记
}
该函数对semid指定的信号量集合中,由sops所指向的包含nsops个元素的,依次执行如下操作:
sem_op>0:将sem_op加到sem_num对应的信号量的计数值上去
sem_op<0:将sem_op加到sem_num对应的信号量的计数值上去
sem_op=0:将sem_num对应的信号量计数为0才返回
sem_flg:0:代表阻塞
1:IPC_NOWAIT,非阻塞,不等待,出错返回
nsops:
相关文章推荐
- 看不懂
- Mybatis-解决字段名与实体类属性名不相同的冲突
- mysql 学习记录(二十五)--mysql日志
- 粒子群算法求解优化问题(c实现)
- android 在eclipse中把局部变量变成成员变量前自动加m
- Daily Scrum 11.7
- robotium 中获取相同类型的自控觉得获取方法(使用Android的ViewGroup控件的getChildAt(index)获取)
- 【用Script Editor创建复杂的对话框】
- 字符集和字符编码(Charset & Encoding)
- Springmvc返回json
- 《leetCode》:Reverse Nodes in k-Group
- log4j.properties 配置详解
- 孩子身高居然长这么快?
- ubuntu 的权限和目录
- [UVA 11517] Exact Change (背包DP)
- 二叉树的后序非递归遍历
- PHP PDOException MySql Error Codes and Messages
- Linux内核原理-进程入门
- JavaScript命名空间
- HDU 1176 免费馅饼(DP)