Linux基础知识2

  • Linux基础知识2已关闭评论
  • 327 人浏览
  • A+
所属分类:教程分享

本篇引见一些Linux历程间通讯IPC相关内容.

1. 历程间通讯 IPC(inter-Process communication)

历程间通讯就是在差别历程之间流传或交流信息,其重要包括以下目标

1)数据传输:一个历程须要将它的数据发送给另一个历程,发送的数据量在一个字节到几兆字节之间。

2)同享数据:多个历程想要操纵同享数据,一个历程对同享数据的修正,别的历程应当马上看到。

3)关照事宜:一个历程须要向另一个或一组历程发送音讯,关照它(它们)发生了某种事宜(如历程住手时要关照父历程)。

4)资本同享:多个历程之间同享一样的资本。为了作到这一点,须要内核供应锁和同步机制。

5)历程掌握:有些历程愿望完整掌握另一个历程的实行(如Debug历程),此时掌握历程愿望能够阻拦另一个历程的一切堕入和异常,并能够实时晓得它的状况转变。

2. 历程间交流数据的要领

1) 文件

父历程把运算效果写入文件中, 子历程去读取文件信息(须要加文件锁)

2) 信号

只能通报一个值 1~64 号信号中的一个

3) 管道

4) 同享内存

5) 音讯行列

6) 信号量集, 与信号没有任何关联

3. 管道的运用

管道有以下特性:

1) 最陈旧的历程间通讯体式格局, unix 最开始运用的历程交流数据的体式格局

2) 以文件作为交流数据的序言, 管道分为匿名管道和定名管道

3) 历史上的管道指的是半双工管道

3.1 匿名管道

重要用于父子历程之间通讯

int pipe ( int pipefd[2] ); pipe()函数会竖立管道,并将文件描述词由参数pipefd数组返回。pipefd : 用于寄存文件描述符 pipefd [0]为管道里的读取端 pipefd [1]则为管道的写入端。返回值 : 若胜利则返回0,不然返回-1,毛病缘由存于errno中。

运用步骤:

int main(){ int _pipe[2]; int ret = pipe(_pipe); if(ret == -1) { printf("creat pipe error!errno code is:%d\n",errno); return -1; } pid_t id = fork(); if(id < 0) { printf("fork error!"); return 2; } else if(id==0) /* 子历程 */ { close(_pipe[0]); /* 关掉读*/ int i = 0; char* buf = NULL; while(i<20) { if(i<10) {  buf = " i am child!"; write(_pipe[1], buf,strlen(buf)+1); /* 写入数据*/ } sleep(1); i++; } } else /* 父历程 */ { char buf[100]; int j = 0; while(j<3) { memset(buf,'\0',sizeof(buf)); int ret = read(_pipe[0],buf,sizeof(buf)); /* 读出数据 */ printf("%s:code is %d\n",buf,ret); j++; } close(_pipe[0]); } return 0;}

3.2 定名管道

两个无关历程之间通讯

编程模子:

int mkfifo(const char *pathname, mode_t mode);pathname,要建立管道文件的途径和称号mode,要建立的管道文件的操纵权限返回值 : 若胜利则返回0,不然返回-1,毛病缘由存于errno中

当 A B 两个历程翻开操纵管道的过程当中, 如果一段封闭管道(管道断裂), 另一端会收到 SIGPIPE , 该信号默许处理体式格局是终了当前历程

4. 同享内存

同享内存许可两个不相关的历程接见统一段物理内存, 因为数据不须要在差别的历程间复制,所以它是在两个正在运转的历程之间通报数据的一种异常有用的体式格局,一个历程向同享内存地区写入数据,同享该地区的一切历程就能够马上看到个中的数据内容

运用步骤:

(1) 键 key的拔取

如果是父子关联的历程间通讯的话,这个标识符用IPC_PRIVATE来替换。如果两个历程没有任何关联,就用ftok()函数算出来一个标识符(或许本身定义一个)运用

key_t key=12345

(2) 服务器历程运用 key 来建立(请求) 同享内存

int shmget ( key_t key, int size, int flag ); shmget函数 : 用于拓荒或指向一块同享内存,返回获得同享内存地区的ID,如果不存在指定的同享地区就建立响应的地区keyt key : 同享内存的标识符int size : 以字节为单元指定须要同享的内存容量int flag : 权限标志,它是这块内存的形式(mode)以及权限标识,形式可取以下值:  IPC_CREAT 新建(如果已建立则返回现在同享内存的id)  IPC_EXCL 与 IPC_CREAT连系运用,如果已建立则返回毛病  将“形式” 和“权限标识”举行或运算,做为第三个参数 如 IPC_CREAT | IPC_EXCL | 0640 个中0640为权限标识,4/2/1 离别示意读/写/实行3种权限,第一个0是UID,第一个6(4+2)示意具有者的权限,第二个4示意同组权限,第3个0示意别人的权限返回值 : 函数挪用胜利时返回同享内存的ID,失利时返回-1。

注:建立同享内存时,shmflg参数最少须要 IPC_CREAT | 权限标识,如果只要IPC_CREAT 则请求的地点都是k=0xffffffff,不能运用;

(3) 映照同享内存, 获得该物理内存的虚拟地点

void *shmat(int shmid, const void *shmaddr, int shmflg);shmat函数 : 用来许可本历程接见一块同享内存的函数,第一次建立同享内存时,任何历程不能接见,要想启用对该同享内存的接见,必需将其衔接到一个历程的地点空间中int shmid : 同享内存的ID,即同享内存的标识char *shmaddr : 同享内存衔接到历程中的肇端地点,如果shmaddr为NULL,内核会把同享内存映照到体系选定的地点空间中;如果shmaddr不为NULL,内核会把同享内存映照到shmaddr指定的位置。int shmflag : 本历程对该内存的操纵形式,能够有两个取值 SHM_RND为读写形式,SHM_RDONLY是只读形式返回值 : 函数挪用胜利时,返回同享内存的肇端地点,失利时返回-1。

注:平常情况下很少须要掌握同享内存衔接的地点,一般都是让体系来挑选一个地点,不然就会使应用程序对硬件的依赖性太高,所以平常把shmaddr设为NULL。

(4) 运用同享内存

相似于 p=malloc(1000);

(5) 消除映照

int shmdt(const void *shmaddr);shmdt函数 : 用于函数删除本历程对这块内存的运用,shmdt()与shmat()相反,是用来制止本历程接见一块同享内存的函数char *shmaddr : 是那块同享内存的肇端地点返回值 : 函数挪用胜利时返回0,失利时返回-1

6) 开释/烧毁同享内存

int shmctl(int shmid, int cmd, struct shmid_ds *buf);shmctl函数 : 掌握对这块同享内存的运用int shmid : 同享内存的ID,即同享内存标识int cmd : 掌握敕令,示意要采用的行动,可取值以下: IPC_STAT 获得同享内存的状况:把shmid_ds构造中的数据设置为同享内存的当前关联值 IPC_SET 转变同享内存的状况:把同享内存的当前关联值设置为shmid_ds构造中给出的值 IPC_RMID 删除同享内存段struct shmid_ds *buf : 构造体指针,IPC_STAT的时刻,获得的状况放在这个构造体中,如果要转变同享内存的状况,用这个构造体指定,shmid_ds构造最少包括以下成员: struct shmid_ds { uid_t shm_perm.uid; uid_t shm_perm.gid; uid_t shm_perm.mode; }返回值 : 函数挪用胜利时返回0,失利时返回-1

长处: 最快的历程间通讯手腕

瑕玷: 须要自行变成处理同享内存的同步接见,平常是经由过程信号量来处理的

5. 音讯行列

音讯行列供应了一个从一个历程向别的一个历程发送一块数据的要领

每一个数据块都被认为是有一个范例,吸收者历程吸收的数据块能够有差别的范例

编程步骤

(1) 键 key 的拔取

如果是父子关联的历程间通讯的话,这个标识符用IPC_PRIVATE来替换。如果两个历程没有任何关联,就用ftok()函数算出来一个标识符(或许本身定义一个)运用

key_t key=12345

(2) 建立/猎取音讯行列

int msgget ( key_t key, int msgflg );msgget函数 : 获得音讯行列标识符或建立一个音讯行列对象key : 标识行列的唯一编号msgflag : 建立音讯行列时, flag 的取值为, IPC_CREAT|IPC_EXCL|权限 获得音讯行列时, flag 的取值为, 0返回值 : 函数挪用胜利时返回0,失利时返回-1,毛病缘由存于error中

(3) 向音讯行列这放入音讯

int msgsnd (int msgid, const void *addr, size_t size, int msgflg );msgsend函数 : 将音讯写入到音讯行列msgid : 音讯放入谁人音讯行列addr : 音讯数据地点size : 音讯的长度msgflag : 发送音讯一般情况下给 0, 壅塞实行, 参数IPC_NOWAIT为不壅塞实行 当音讯行列满了的情况下, 如果给 0, 就等到能够放进去位为止( 接收到其他 信号也大概住手, 如 ctrl +c ), IPC_NOWAIT 则会直接报错返回值 : 函数挪用胜利时返回0,失利时返回-1,毛病缘由存于error中

从音讯行列这掏出音讯

ssize_t msgrcv(int msgid, void *addr, size_t size, long msgtype, int msgflg);msgrcv函数 : 从音讯行列读取音讯msgid : 晓得从哪一个音讯行列这掏出音讯addr : 掏出的音讯存储什么位置size : 希冀取到的音讯的长度msgtype : 指定掏出谁人范例的音讯 =0, 接收恣意范例的音讯 >0, 接收特定范例的音讯 <0, 接收音讯范例小于即是 |msgtpye|的音讯( msgtyoe 的绝对值), 根据音讯范例从小到大返回接收的音讯msgflag : 发送音讯一般情况下给 0, 壅塞实行, 参数IPC_NOWAIT为不壅塞实行 IPC_NOERROR, 运用这个参数时如果吸收的字节长度比发送的长, 则会把过剩的抛弃, 如果不加这个参数则会报错返回-1返回值 : 函数挪用胜利时返回0,失利时返回-1,毛病缘由存于error中

(4) 烧毁/删除音讯行列

int msgctl(int msgid, int cmd, struct msgid_ds *buf);msgctl函数 : 猎取和设置音讯行列的属性, 烧毁音讯行列msgid : 须要举行操纵的音讯行列的 idcmd : IPC_RMID,烧毁音讯行列, 晓得没有历程运用才真正烧毁, 相似与 unlink IPC_STAT, 经由过程 buf 参数返回音讯行列的属性信息 IPC_SET,经由过程buf参数设置音讯行列属性信息buf : 与 IPC_STAT 一同运用的时刻返回音讯行列存的属性信息返回值 : 函数挪用胜利时返回0,失利时返回-1,毛病缘由存于error中

(5) 发送音讯花样

音讯分为有范例音讯和无范例音讯

1) 无范例音讯简朴, 然则接收音讯时无细分, 只能先进先出

2) 有范例的音讯编程比较范例, 接收能够根据音讯范例先进先出

花样以下所示

struct s_msg{ /*msgp定义的参照花样*/ long type; /* 必需大于0,音讯范例 */ char mtext[256]; /*音讯正文,能够是其他任何范例*/} msgp;

6. 信号量(集)

信号量是一个计数器( 数字), 掌握接见同享资本的最大并行历程总数, 运用时平常是给一个初始值( int 范例的变量)

如果该同享资本许可两个同时两个历程运用, 初始值设置为2, 如果有一个历程运用该资本则该计数-1, 如果有另一个历程摒弃该资本计数+1, 如果计数为 0, 则不许可新的历程来接见同享资本, 新的历程壅塞守候, 直到计数从新大于 0 能够完成-1 操纵, 消除壅塞

如果由多个同享资本须要掌握接见, 继承要多个信号量, 把多个信号量存入一个, 数组中, 这个数组就叫信号量集

信号量集的编程步骤:

(1) 获得/肯定 key

key_t key=nnnn; /*本身定义*/key_t ftok = (pathname, proj_id); /*运用ftok函数生成*/pathname : 存在的文件的称号proj_id : 1~255 之间的恣意值返回值 : 经由过程 inode 值和 proj_id 编码生成的 key_t

2) 建立/猎取信号量集

int semget(key_t key, int nsems, int semflg);semget函数 : 建立一个新的信号量或猎取一个已存在的信号量的键值key : 建立/猎取的信号量集对应的 key 键nsems : 建立的信号量鸠合包括的信号量的个数semflg : 信号量的建立体式格局或权限,有IPC_CREAT,IPC_EXCL IPC_CREAT如果信号量不存在,则建立一个信号量,不然猎取 IPC_EXCL只要信号量不存在的时刻,新的信号量才竖立,不然就发生毛病返回值 : 胜利返回对应的信号量集的 id , 失利返回-1,毛病缘由存于error中

3) 设置信号量的初始值

int semctl(int semid, int semnum, int cmd, ...);semctl函数 : 对信号量举行设置semid : 要操纵哪一个信号量集semnum : 指定要操纵该鸠合中的哪一个信号量cmd : 对该信号量实行如何的操纵 IPC_STAT, 从信号量集上检索semid_ds构造,并存到semun联合体参数的成员buf的地点中 IPC_SET, 设置一个信号量鸠合的semid_ds构造中ipc_perm域的值,并从semun的buf中掏出值 IPC_RMID, 从内核中删除信号量鸠合 SETVAL, 用联合体中val成员的值设置信号量鸠合中单个信号量的值args : 第四个参数取决于cmd参数的取值 union semun { short val; /*SETVAL用的值*/ struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds构造*/ unsigned short* array; /*SETALL、GETALL用的数组值*/ struct seminfo *buf; /*为掌握IPC_INFO供应的缓存*/ } arg;返回值 : 胜利返回大于或即是0, 失利返回-1,毛病缘由存于error中

4) 掌握队关联资本的并发接见

在运用同享资本之前给信号量-1,-1 胜利, 就操纵同享资本, 运用终了以后信号量+1,-1 不胜利, 则壅塞

int semop(int semid, struct sembuf *sops, unsigned nsops);semop函数 : 完成对信号量的操纵semid : 要操纵哪一个信号量集nsops : 指明要操纵的信号量的个数sops : 对信号量集进举行哪一种操纵该构造提包括的数据范例{ sem_num; // 要操纵鸠合中的第几个 sem_op; // 平常有两个值,-1 带表减 1 操纵,1 代表加 1 操纵 sem_flg; // 取0,操纵不胜利壅塞,取IPC_NOWAIT不壅塞直接返回}返回值 : 胜利返回0, 失利返回-1,毛病缘由存于error中

5) 信号量集不再运用时, 烧毁信号量集

semctl函数合营IPC_RMID参数运用

总结:

(1) 同享内存是最快的 IPC 接见机制, 适用于历程间通报大批量的数据, 但自行编程掌握多历程队同享内存的合作接见, 平常运用信号量处理

(2) 如果举行间通报的数据具有很强的数据性, 能够斟酌音讯行列完成

(3) 历程间的同步更多的是斟酌信号量机制

(4)操纵同享内存、 音讯行列、 信号量集的敕令

ipcs -c 列出体系中同享内存、 音讯行列、 信号量集

ipcrm -M key 删除指定的同享内存

ipcrm -Q key 删除指定的音讯行列

腾讯云双十一活动