Linux系统编程之进程通信(学习笔记)

Linux系统编程中,进程通信常用的有六种:管道,信号,IPC通信中的共享内存、消息队列、信号量集

一、无名管道(只用于有亲缘关系的进程、并且无文件节点)

int pipe(int pipefd[2]) 创建一个无名管道

pipefd[0] 代表读 pipefd[1] 代表写

有读写阻塞

读阻塞:当一个进程试图从没有内容管道里面读取数据时,那么该进程被阻塞,直到管道里面具有内容。

写阻塞:管道具有一定缓存空间,当缓存被填满的时候,若进程试图往进程里面写数据,那么该进程会被阻塞,直到管道中的数据没有被填满。

二、有名管道(有文件节点)

1、可以通过mkfifo函数打开一个有名管道,也可以直接当作命令行来创建

2、只能通过文件io进行读写

3、有读写阻塞

三、标准流管道(只能通过标准io读写)

FILE *popen(const char *command,const char *type); 打开一个标准流管道

int pclose(FILE *stream) 关闭一个标准流管道

四、信号

kill -l 查看所有信号

信号9和信号19不能被更改

较常使用的信号:

 SIGINT:用户按下组合 Ctrl 键+c 键时,向正在运行的进程发送一则信号。默认动作为终止进程。 

  SIGALRM:定时器超时,超时的时间由系统调用 alarm 设置。可以理解为闹钟,时间到了默认动作为终止进程。 

  jobs命令 可以查看现有暂停的任务

  fg命令可以继续暂停的任务

  

  //alarm()定时给自身发送闹钟信号 默认是结束进程

头文件:#include <unistd.h>

原型:unsigned int alarm(unsigned int senconds);

参数:unsigned int senconds ---》表示设定的时间(单位:秒)

         若你设置为0,相当于取消设定的闹钟

  sighandler_t signal(int signum,sighandler_t handler);信号处理函数

        handler: 第一种:SIG_DFL 对信号采用默认处理方式

         第二种:SIG_IGN 忽略该信号

         第三种:信号处理函数的名称--void 函数名(int arg)

     

五、IPC通信

ipcs 显示所有的ipc对象

ipcs -q 消息队列

ipcs -m 共享内存

ipcs -s 信号量集

ipcrm -大写key -小写id 删除

(1)共享内存

基本单位是4k(4096bytes)

多进程使用共享内存的流程:

第一步:申请一块共享内存

第二步:多进程打开同一块共享内存

第三步:多进程将共享内存映射到自己的进程地址空间地址上。

第四步:多进程通过自己的映射区进行读写,完成通信(间接的使用物理空间的内存)

第五步:多进程取消共享内存在自身进程空间地址的映射。

第六步:删除共享内存

所需函数原型:

key_t ftok(const char *pathname,int proj_id);获取key值文件跟id可以随便写

int shmget(key_t key,size_t size,int shmflg);申请共享内存

成功则返回共享内存id

shmflg:IPC_CREAT | 0666  //创建并且设置读写权限,如果不给权限,返回的key值为0xffffffff没办法用

void *shmat(int shmid,const void *shmaddr,int shmflg); 内存映射到本进程的地址空间上

shmaddr:NULL 自动分配 shmflg:0 可读可写

返回内存应映射后的地址

int shmdt(const void *shmaddr);取消内存映射

int shmctl(int shmid,int cmd,struct shmid_ds *buf) 内存控制函数 现阶段主要用于删除内存映射

cmd:IPC_STAT(查看状态) IPC_SET(设置)IPC_RMID(删除)

需要取消内存映射后才可以删除

六、消息队列

有编号

先进先出

具有读阻塞

int msgget(key_t key,int msgflg);打开消息队列

msgflg:IPC_CREAT|0600

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg); 消息队列发送函数

成功 返回消息队列的ID,失败的话 返回-1

msgflg:0(保留阻塞)|IPC_NOWAIT(无阻塞)|MAG_ERROR

 第二个参数需要先定义:struct msgbuf {

               long mtype; /* message type, must be > 0 */

               char mtext[20]; /* message data */

           };

ssize_t msgrcv(int msqid , void *msgp,size_t msgsz,long msgtyp,int msgflg);消息队列接收函数

msgtyp:接收消息的编号

int msgctl(int msqid,int cmd,struct msqid_ds *buf);消息队列控制函数  现阶段主要用于删除

七、信号量集/信号灯

信号量是一个非负整数

PV操作是基于对信号量值进行的操作,当信号量值等于0,此进程再使用该信号量的时候会进入阻塞,

当信号量的值大于0时候,此进程使用该信号量才会继续执行。

int semget(key_t key, int nsems, int semflg);

int nsems :创建信号量集中的信号量数目,如果引用一个现存的信号量集合,

则将nsems 指定为0。

--也可以为当信号量集里面信号量的数量

int semflg:IPC_CREAT|0600

成功返回信号量集的id

int semctl(int semid, int semnum, int cmd, union semun arg);信号量集控制函数

.int semnum: 要操作的信号量集中的指定信号量编号即下标,编号从0开始,

当使用信号量集时才会被用到。

cmd:IPC_RMID:从系统中删除信号量。

IPC_GETVAL或GETVAL: 根据 semmun 指定的编号返回指定信号量的当前值,

 此时该函数返回值就是你要获得的信号量的值,不再是 0 或-1)

 IPC_SETVAL或SETVAL: 根据 semmun 指定的编号设定相应信号的值,修改的值需要使用第四个参数 union semun arg,然后要设置值放arg.val在)

 简单来说就是将信号量值设置为arg的val值

 GETALL(获取所有信号量的值,此时该函数第二个参数为0,

 此时需要用到第四个参数union semun arg并且会将所有信号的值存入arg.array所指向的数组(unsigned short)

 的各个元素中(每个元素都对应一个信号量的值))

 SETALL(设置所有信号量的值,此时该函数第二个参数为 0,此时需要用到第四个参数union semun arg,

 将 arg.array 指向的数组的所有元素的值一一对应设定到信号量时集中)

 使用共用体时需要自己定义:

 union semun{

 int val; /* Value for SETVAL */

 struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */

 unsigned short *array; /* Array for GETALL, SETALL */

 struct seminfo *__buf; /* Buffer for IPC_INFO (Linux-specific) */

}

返回值:

成功,根据cmd的值的不同而返回不同的值。

cmd为IPC_STAT、IPC_SETVAL、IPC_RMID则函数返回0。

cmd为IPC_GETVAL则函数返回信号量的当前值。

错误: -1

int semop(int semid, struct sembuf *sops, unsigned nsops); 操作信号量集

第二个参数:struct sembuf 

{

 unsigned short sem_num; /* 信号量在信号量集中的编号 一般从0 开始,0表示第1个,1表示第2 个,nsems - 1表示最后一个。*/

 short sem_op; /* 信号量变化值 PV操作*/

 short sem_flg; /* 一组标志 直接给0值 */

 sem_flg:信号量操作的属性标志 写0表示正常操作

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值