第 9 章 Linux进程通信_第1页
第 9 章 Linux进程通信_第2页
第 9 章 Linux进程通信_第3页
第 9 章 Linux进程通信_第4页
第 9 章 Linux进程通信_第5页
已阅读5页,还剩56页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第9章Linux进程通信内容提要进程通信概述管道内存映射SystemVIPCPOSIXIPC文件锁9.1进程通信概述进程通信概述进程需彼此协同、交换和共享数据,由于进程的用户空间各自独立,无法直接沟通,但它们共享内核空间和文件系统,可借助内核和文件来实现进程间的通信。应用编程接口分类API功能描述管道pipe建立无名管道Popen/pclose打开/关闭命令的标准输入或输出mkfifo创建命名管道内存映像文件mmap/munmap建立/解除文件至内存的映射SystemVIPC信号量semget创建/打开systemv信号量semop申请/释放systemv信号量semctl操作systemv信号量消息队列msgget创建/打开systemv消息队列msgrcv从systemv消息队列接收消息msgsnd向systemv消息队列发送消息msgctl操作systemv消息队列共享内存shmget建立/打开systemv共享内存shmat/shmdt建立/删除systemv共享内存映射shmctl操作systemv共享内存POSIXIPC信号量sem_open/sem_close/sem_unlink打开/关闭/删除POSIX信号量sem_wait/sem_post等待/释放POSIX信号量Sem_init/sem_destroy初始化/注销POSIX无名信号量消息队列mq_open/mq_close/mq_unlink打开/关闭/删除POSIX消息队列mq_getattr/mq_setattr获取/设置POSIX消息队列属性mq_receive/mq_send收发POSIX消息共享内存shm_open/shm_unlink打开/删除POSIX共享内存文件锁flock锁定/解锁文件9.2管道管道概述管道是一种进程间的单向数据传输机制,基于先进先出的字节流,管道有两个端点,一端用于写入数据,另一端用于从管道读取,读取的数据会从管道中移走。根据接口形式的不同,管道可分为无名管道和命名管道。管道的分类1.无名管道无名管道因无对应的管道文件而得名,借助内存而非外部文件实现通信,通常为关联的进程间建立通道。2.命名管道命名管道是建立于文件系统的特殊文件,借助文件接口实现进程间通信。创建无名管道头文件

#include<unistd.h>函数原型

int

pipe(intfd[2]);功能 创建无名管道。参数

pipefd[2]:对文件描述符。

flags:操作方式。返回值 成功返回0,否则返回-1。

无名管道的实现dentry(目录项)dentryf_opnamed_inodefile(文件描述)task_struct(进程控制块)fd0123465fd[](文件描述符表)file(文件描述)物理页写端读端dentryf_opread_pipe_fops(文件操作集)write_pipe_fops(文件操作集)..read.write.管道创建命名管道头文件

#include<sys/types.h> #include<sys/stat.h>函数原型

int

mkfifo(constchar*pathname,mode_tmode);功能 创建命名管道。参数

pathname:文件路径名。

mode:存取权限。返回值 成功返回0,失败返回-1。实例分析charbuffer[BUFSIZ];int

main(int

argc,char*argv[]){

intpipefd[2];

pipe(pipefd);

pid_t

pid=fork(); if(pid==0){ close(pipefd[1]); while(read(pipefd[0],&buffer,1)>0) write(1,&buffer,1); write(1,"\n",1); close(pipefd[0]); _exit(0); }else{ close(pipefd[0]); write(pipefd[1],argv[1],strlen(argv[1])); close(pipefd[1]);

wait(NULL); exit(0); }}9.3内存映射内存映射概述

内存映射是一种将文件的某个区域

映射至进程用户地址空间的技术。内存文件为一种特殊类型的文件,其内容存储于内存页中,例如,位于内存文件系统中的文件属于该类文件,利用内存映射可将内存文件的某个区域同时映射至多个进程的用户地址空间,从而实现进程间的通信。POSIXIPC正是通过在内存文件上建立内存映射构建。

mmap/munmap函数头文件

#include<sys/mman.h>函数原型

void*mmap(void*addr,size_t

length,int

prot,int

flags,int

fd,off_toffset);

int

munmap(void*addr,size_tlength);功能 建立/解除内存映射。参数

addr:映射区起始地址。

length:映射区大小。

prot:存取权限。

flags:映射方式。

fd:文件描述符。

offset:文件偏移量。返回值

mmap函数成功返回映射区起始地址,失败返回MAP_FAILED。

munmap函数成功返回0,失败返回-1。实例分析int

main(int

argc,char*argv[]){

int

fd=open("/dev/zero",O_RDWR,0); char*anon,*zero;anon=(char*)mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_ANON|MAP_SHARED,-1,0);zero=(char*)mmap(NULL,4096,PROT_READ|PROT_WRITE,MAP_FILE|MAP_SHARED,fd,0);

strcpy(anon,argv[1]);

strcpy(zero,argv[1]);

printf("anonymous:%s\tzero-backed:%s\n",anon,zero); switch((fork())){ case0:

strcpy(anon,argv[2]);

strcpy(zero,argv[2]);

munmap(anon,4096);

munmap(zero,4096);

close(fd); return0; } sleep(3);

printf("anonymous:%s\tzero-backed:%s\n",anon,zero);

munmap(anon,4096);

munmap(zero,4096);

close(fd); return0;}9.4SystemVIPC内容提要SystemVIPC概述

SystemV信号量

SystemV消息队列

SystemV共享内存SystemVIPC概述SystemVIPC源自SystemV系统,是一种传统的进程间通信的接口规范,在各类传统Unix系统中得到广泛使用,它由信号量、消息队列和共享内存三部分构成,可实现进程间的同步、数据传输和数据共享,

自Linux诞生之初,Linux内核就提供了对SystemVIPC的支持。

SystemVIPC通过在内核中创建IPC对象实现,每个IPC对象对应一个唯一的ID。SystemV信号量

信号量表示某种资源的数量,资源的数量可反映到信号量的数值上,当信号量大于0时,表示有资源可供使用,当信号量等于0时,表示已无资源可用,申请资源者需要等待。

SYSTEMV信号量用信号量集表示,由若干信号量组成,可同时反映多种资源的状态,一次可支持对一个或多个信号量的原子操作。SystemV信号量的操作步骤(1)创建/打开一个SystemV信号量集。(2)初始化SystemV信号量(3)申请/释放SystemV信号量(4)当SystemV信号量不再使时,将其删除。semget函数头文件

#include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h>函数原型

int

semget(key_tkey,int

nsems,int

semflg);功能 获得或创建信号量。参数

key:IPC对象标识。

nsems:信号量的数量。

semflg:存取权限和操作方式。返回值 成功返回信号量的标识,失败返回-1。信号量相关状态信息内核用数据结构记录每一种信号量的状态信息,例如:unsignedshortsemval;//信号量当前值unsignedshortsemzcnt;//等待信号量变为0的进程/线程的数量unsignedshortsemncnt;//等待释放信号量的进程/线程数量pid_t

sempid//最近一次修改信号量的进程ID

信号量的申请与释放会修改semval,当无信号量可用时,调用者进程便会进入semncnt和semzcnt关联的等待队列。semop函数头文件

#include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h>函数原型

int

semop(int

semid,struct

sembuf*sops,unsignednsops);功能 获得/释放信号量。参数

semid:信号量标识。

sops::信号量数组。

nsops:信号量数量。返回值 成功返回0,失败返回-1。semop函数(续)struct

sembuf{ushort

sem_num; //在信号量数组中的索引shortsem_op; //操作类型shortsem_flg; //操作标志};sembuf结构中成员变量sem_op描述信号量的操作类型参数sem_op含义sem_op>0指定信号量与sem_op相加,释放更多的信号量,唤醒正在等待该信号量的进程/线程sem_op=0等待指定信号量变为0sem_op<0指定信号量与sem_op相加,若值大于等于0,表示获得信号量,否则等待semctl函数头文件

#include<sys/types.h> #include<sys/ipc.h> #include<sys/sem.h>函数原型

int

semctl(int

semid,int

semnum,int

cmd,...);功能 信号量的控制操作。参数

semid:信号量标识。

semnum:在信号量集中的索引。

cmd:操作类型。返回值 成功返回值由具体操作决定,失败返回-1。semctl函数(续)unionsemun{

int

val;//用于设置信号量的值

struct

semid_ds*buf;//缓存地址,用于IPC_STAT和IPC_SETunsignedshort*array;//数组地址,用于GETALL和SETALL

struct

seminfo*__buf;//缓存地址,用于IPC_INFO};参数cmd含义GETVAL获得信号量的值SETVAL设置信号量的值GETPID获得最后一次操作信号量的进程GETNCNT获得正在等待信号量的进程数GETZCNT获得等待信号量值变为0的进程数IPC_RMID删除信号量集,唤醒所有等待的进程/线程3SystemV消息队列

消息队列是存在于内核中的消息列表,一个进程可将消息发送至消息队列,另一个进程则可从消息队列中获取消息。栈堆数据代码栈堆数据代码进程1进程2消息队列Linux内核Linux内核SystemV消息队列的操作步骤(1)建/打开SystemV消息队列。(2)接收/发送SystemV消息。(3)当SystemV消息队列不再使用时,将其删除。msgget函数头文件

#include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h>函数原型

int

msgget(key_tkey,int

msgflg);功能 创建/打开SystemV消息队列参数

key:IPC对象标识。

msgflg:存取权限和操作方式。返回值 成功返回消息队列标识,失败返回-1。msgrcv/msgsnd函数头文件

#include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h>函数原型

ssize_t

msgrcv(int

msqid,void*msgp,size_t

msgsz,long

msgtyp,int

msgflg);

int

msgsnd(int

msqid,constvoid*msgp,size_t

msgsz,int

msgflg);功能接收/发送SystemV消息。参数

msqid:消息队列的标识。

msgp:消息地址。

msgsz:消息大小(字节数)。

msgtyp:接收消息类型。

msgflg:操作方式。返回值 成功返回0,失败返回-1。struct

msgbuf{longmtype;//消息类型,必须大于0charmtext[1];//消息,具体结构用户可自定义};msgctl函数头文件

#include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h>函数原型

int

msgctl(int

msqid,int

cmd,struct

msqid_ds*buf);功能控制SystemV消息队列的属性。参数

msqid:消息队列标识。

cmd:操作类型。

buf:指向操作的数据。返回值 成功返回0,失败返回-1。msgctl函数struct

msqid_ds{

struct

ipc_perm

msg_perm;

struct

msg*msg_first; //指向消息队列的首

struct

msg*msg_last; //指向消息队列的尾

__kernel_time_t

msg_stime; //最后发送时间

__kernel_time_t

msg_rtime; //最后接收时间

__kernel_time_t

msg_ctime; //最后修改时间

unsignedshortmsg_cbytes; //当前消息队列的字节数

unsignedshortmsg_qnum; //消息队列中的消息数

unsignedshortmsg_qbytes; //消息队列的最大字节数

__kernel_ipc_pid_t

msg_lspid; //最后发送消息的进程ID__kernel_ipc_pid_t

msg_lrpid; //最后接收消息的进程ID};参数cmd含义IPC_RMID删除消息队列IPC_STAT获取消息队列的状态IPC_SET改变消息队列的存取权限struct

ipc_perm{

key_tkey; //IPC对象标识

uid_t

uid; //用户ID

gid_t

gid; //用户组ID

uid_t

cuid; //创建用户ID

gid_t

cgid; //创建用户组IDunsignedshortmode; //权限分配

unsignedshortseq; //序列号};SystemV共享内存

将同时映射至不同进程用户空幻的物理内存称为共享内存,物理内存可由若干不连续的物理页构成,共享内存在不同进程用户空间的地址未必相同。内核栈堆数据代码内核栈堆数据代码进程1进程2物理内存映射映射1.SYSTEMV共享内存的操作步骤(1)创建/打开SystemV共享内存。(2)将SystemV共享内存映射至调用者进程的用户空间。(3)当SystemV共享内存不再使用时,将映射接触。shmget函数头文件

#include<sys/ipc.h> #include<sys/shm.h>函数原型

int

shmget(key_tkey,intsize,int

shmflg);功能 创建/获得systemv共享内存。参数

Key:共享内存标识。

size:共享内存大小。

shmflg存取权限和操作方式。返回值 成功返回消息队列标识,失败返回-1。shmat/shmdt函数

头文件

#include<sys/types.h> #include<sys/shm.h>函数原型

void*shmat(int

shmid,constvoid*shmaddr,int

shmflg);

int

shmdt(constvoid*shmaddr);功能 建立/解除SystemV共享内存的内存映射。参数

shmid:IPC对象标识。

shmaddr:映射地址。

shmflg:权限和操作方式。返回值 成功返回映射的地址,失败返回-1。shmctl函数头文件

#include<sys/types.h> #include<sys/shm.h>函数原型

int

shmctl(int

shmid,int

cmd,struct

shmid_ds*buf);功能 操作systemv共享内存。参数

shmid:IPC对象标识。

cmd:操作命令。

buf:共享内存属性地址。返回值 成功返回0,失败返回-1。shmctl函数struct

shmid_ds{

struct

ipc_perm

shm_perm; //存取权限

int

shm_segsz; //共享内存大小

__kernel_time_t

shm_atime; //最后映射时间

__kernel_time_t

shm_dtime; //最后解除映射时间

__kernel_time_t

shm_ctime; //最后修改时间

__kernel_ipc_pid_t

shm_cpid; //创建进程ID__kernel_ipc_pid_t

shm_lpid; //最近操作进程IDunsignedshort shm_nattch; //建立映射的进程数};参数cmd描述IPC_STAT获取共享内存的状态IPC_SET设置共享内存的权限IPC_RMID删除共享内存IPC_LOCK锁定共享内存,使共享内存不被交换出去IPC_UNLOCK解锁共享内存9.5POSIXIPC内容提要POSIXIPC概述POSIX信号量

POSIX消息队列POSIX共享内存POSIXIPC概述

为了消除各类Unix间的差异,POSIX设计了一套具有更高可移植性的IPC接口标准,相较于SystemVIPC,POSIXIPC语法较为简洁,它同样支持信号量、消息队列和共享内存。在较新的Linux内核中实现了对POSIXIPC的支持。POSIX信号量POSIX信号量是一种进程间同步的控制机制,信号量用整数表示,通常代表某种资源的数量。进程通过减操作申请获得信号量,通过加操作申请释放信号量,当信号量值为0时,试图获取信号量的进程挂起,直至其他进程释放信号量;反之,当信号量已达上限,试图释放信号量的进程挂起,直至其他进程获取了信号量。POSIX信号量的分类POSI命名信号量在Linux系统中,命名信号量存储于文件系统tmpfs,tmpfs通常挂载至/dev/shm,当创建一个新POSIX命名信号量时,同名文件会出现在/dev/shm目录。2.POSIX无名信号量POSIX无名信号量在文件系统上无对应的文件,如同无名管道一样,可用于父子进程及其线程间的同步控制。POSIX信号量的操作步骤1.创建/打开POSIX信号量。1.申请/释放POSIX信号量。3.当完成对信号量的操作,及时关闭信号量。4.当所有进程都关闭了信号量,将信号量删除。创建/打开/关闭/删除POSIX命名信号量。(1)sem_open/sem_close/sem_unlink函数头文件

#include<fcntl.h> #include<sys/stat.h> #include<semaphore.h>函数原型

sem_t*sem_open(constchar*name,int

oflag);

sem_t*sem_open(constchar*name,int

oflag,mode_tmode,unsignedintvalue);

int

sem_close(sem_t*sem);

int

sem_unlink(constchar*name);功能 创建/打开/关闭/删除POSIX命名信号量。参数

name:信号量名称。

oflag:操作方式。

mode:权限设置。

value:信号量初始值。返回值

sem_open函数成功返回信号量地址,失败返回SEM_FAILED。申请/释放POSIX信号量(2)sem_wait/sem_post函数头文件

#include<semaphore.h>函数原型

int

sem_wait(sem_t*sem);

int

sem_timedwait(sem_t*sem,conststruct

timespec*abs_timeout);

int

sem_post(sem_t*sem);功能 申请获取/释放POSIX信号量。参数

sem:信号量对象。

abs_timeout:超时时间。返回值 成功,返回0,失败,返回-1。初始化/注销POSIX无名信号量(3)sem_init/sem_destroy函数头文件

#include<semaphore.h>函数原型

int

sem_init(sem_t*sem,int

pshared,unsignedintvalue)

int

sem_destroy(sem_t*sem)功能 初始化/注销POSIX无名信号量。参数

sem:信号量。

pshared:共享标志。

value:信号量的初始值。返回值 成功,返回0,否则,返回-1。POSIX无名信号量在文件系统上无对应的文件,如同无名管道一样,基于内存实现,可用于父子进程及其线程间的同步控制。POSIX消息队列POSIX消息队列是一种进程间以消息为单位的数据传输机制,消息以队列形式储存,并为消息定义优先级,优先级高的消息会被优先处理。POSIX消息队列的实现在Linux系统中,POSIX消息队列存储于mqueue文件系统,若将mqueue文件系统挂载至/dev/mqueue目录,新建的消息队列会在/dev/mqueue生成相应的文件.POSIX消息队列的操作步骤1.创建/打开一个POSIX消息队列。2.接收/发送消息。3.当完成对消息队列的操作,应及时关闭消息队列。4.当所有进程不再使用消息队列时,应将消息队列删除。创建/打开/关闭/删除POSIX消息队列(1)mq_open/mq_close/mq_unlink函数头文件

#include<fcntl.h> #include<sys/stat.h> #include<mqueue.h>函数原型

mqd_t

mq_open(constchar*name,int

oflag);

mqd_t

mq_open(constchar*name,int

oflag,mode_t

mode,struct

mq_attr*attr);

int

mq_close(mqd_t

mqdes);

int

mq_unlink(constchar*name);功能 创建/打开/关闭/删除POSIX消息队列。参数

name:POSIX消息队列名称。

oflag:操作方式。

mode:访问权限。

attr:属性地址。返回值

mq_open函数成功返回消息队列描述符,失败返回-1。struct

mq_attr{longmq_flags;//收发信息是否阻塞,取值为0或O_NONBLOCKlongmq_maxmsg;//发送消息数量上限

longmq_msgsize;//每条消息的最大上限

longmq_curmsgs;//当前消息的数量};获取/设置POSIX消息队列属性(2)mq_getattr/mq_setattr函数头文件

#include<mqueue.h>函数原型

int

mq_getattr(mqd_t

mqdes,struct

mq_attr*attr);

int

mq_setattr(mqd_t

mqdes,conststruct

mq_attr*newattr,struct

mq_attr*oldattr);功能 获取/设置POSIX消息队列属性。参数

mqdes:消息队列描述符。

attr:属性地址。

newattr:新属性地址。

oldattr:原属性地址。返回值 成功返回0,失败返回-1。接收/发送消息(3)mq_receive/mq_send函数头文件

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论