欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux进程间通信学习笔记

程序员文章站 2022-06-26 14:33:49
...

进程间通信

进程间通信(IPC)是指在不同进程之间传播或交换信息

IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信息量、共享存储、Socket、Streams等。其中Socket、Streams支持不同主机上的两个进程IPC

无名管道

通常指无名管道,是UNIX系统IPC最古老的形式

特点
  1. 半双工(只能同时进行一组读写),具有固定的读端和写端
  2. 只能用于具有亲缘关系的进程之间的通信(父子进程/兄弟进程)
  3. 可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write等函数。但它不是普通的文件,不属于其他任何文件系统,只存在内存中。
  4. 管道数据被读取,就没了
原型
#include <unistd.h>
int pipe(int fd[2]);		
//返回值:若成功返回0,失败返回-1

当一个管道建立时,其会创建两个文件描述符:

fd[0]为读而打开,fd[1]为写而打开 用close/write/read 操作

​ 读管道 会等到 管道内有数据再读

命名管道 FIFO

命名管道,是一种文件类型

特点
  1. FIFO可以在无关的进程之间交换数据,与无名管道不同
  2. FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统
原型

mode与open的mode相同。一旦创建FIFO,就可以用一般的文件I/O函数操作它

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);

当open一个FIFO时,是否设置非阻塞标志(O_NONBLOCK)的区别

  • 若没指定O_NOBLOCK(默认),只读open要阻塞到某个其他进程为写而打开此FIFO。只写同理
  • 若制定了O_NONBLOCK,则只读open立即返回。而只写open将出错返回-1。如果没有进程已经为读而打开该FIFO,其errno置ENXIO。

消息队列

消息列表,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。

特点
  1. 消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级
  2. 消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除
  3. 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取
原型
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
//创建或打开消息队列:成功返回队列ID,失败返回-1
//flg 中还要包括权限


int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//添加消息:成功返回0,失败返回-1

size_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
//读取消息:成功返回消息数据长度,失败返回-1

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
//控制消息队列:成功返回0,失败返回-1
//msgctl可以清除消息队列  IPC_RMID

在以下两种情况下,msgget将创建一个新的消息列表:

  • 如果没有与键值key相对应的消息队列,且flag中包含了IPC_CREAT标志位
  • key参数为IPC_PRIVATE
ftok

系统IPC键值的格式转换函数

系统建立IPC通讯(消息队列、信号量和共享内存)时必须指定一个ID值。通常情况下,该id值通过ftok函数得到。

#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(const char *pathname, int proj_id);

共享内存

  1. 创建/打开共享内存
  2. 映射
  3. 数据操作
  4. 释放共享内存
原型
#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg);
//创建或获取一个共享内存:成功返回共享内存ID,失败返回-1

void *shmat(int shmid, const void *shmaddr, int shmflg);
//连接共享内存到当前进程的地址空间:成功返回指向共享内存的指针,失败返回-1

int shmdt(const void *shmaddr);
//断开与共享内存的连接:成功返回0,失败返回-1

int shmctl(int shmid, int cmd, struct shmid_ds *buf);
//控制共享内存的相关信息:成功返回0,失败返回-1
//IPC_RMID

共享内存大小必须以兆(1024)对齐

信号

对于Linux来说,实际信号是软中断

信号的处理方式有三种忽略捕捉默认动作

  • 忽略信号,大多数信号能使用这种方式处理,但有两种不能被忽略(SIGKILL和SIGSTOP)
  • 捕捉信号,写一个信号处理函数,告诉内核
  • 默认动作,man 7 signal

ps -aux|grep XXX 查看进程

kill -9 数字 杀死进程

信号处理函数的注册

入门函数:signal

发:kill() 操作函数:signal()

#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_thandler);
//SIG_IGN 忽略

高级函数:sigaction

收信号:1.用什么绑定函数 2.如何读出消息

#include <signal.h>

int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
//oldact  做备份

struct sigaction {
void     (*sa_handler)(int);
//配置信号处理程序,不接受任何数据,SIG_IGN为忽略   
void     (*sa_sigaction)(int, siginfo_t *, void *);
//配置信号处理程序,能够接收额外数据
//配置1.num  2.结构体 3.指针(NULL无数据 非NULL有数据)
//2.结构体 pid谁发 int数据
sigset_t   sa_mask;
//阻塞关键字的信号集,可以再调用捕捉函数之前,把信号添加到信号阻塞
int        sa_flags;
//影响信号的行为	   SA_SIGINFO标识能够接收数据
};

发信号:1.用什么发 2.怎么放入消息

sigqueue

#include <signal.h>

int sigqueue(pid_t pid, int sig, const union sigval value);

union sigval {
int   sival_int;
void *sival_ptr;
};

信号处理发送函数

信号量

是一个计数器,用于实现进程间的互斥与同步,而不是用于存储进程间通信数据

特点
  1. 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存
  2. 信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作
  3. 每次对信号量的PV操作不仅限于对信号量值加1或减1,可以加减任意正整数
  4. 支持信号量组
临界资源

多道程序系统中存在许多进程,它们共享各种资源,然而有很多资源一次只能供一个进程使用。一次仅允许一个进程使用的资源称为临界资源。

信号量集
P操作:拿锁 semop
V操作:放锁 semop
原型

Linux下的信号量函数都是在通用的信号量数组上进行操作,而不是在一个单一的二值信号量上进行操作

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);
//创建或或获取一个信号量组:成功返回信号量集ID,失败返回-1

int semop(int semid, struct sembuf *sops, unsigned nsops);
//对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1

int semctl(int semid, int semnum, int cmd, ...);
//控制信号量的相关信息 cmd初始化SETVAL
					//cmd销毁IPC_RMID

struct sembuf
{
unsigned short sem_num;  /* 信号量集中的第几个信号量 */
short          sem_op;   /* +- 锁*/
short          sem_flg;	/*SEM_UNDO维护进程对信号量的调整值*/
}

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) */
};//semctl第四个参数 设置val(锁的数量)

相关标签: linux