ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

linux当中的六大进程间通信方式

linux当中的六大进程间通信方式 IPC-InterProcess Communication管道 (Pipe)传输无格式的字节流半双工匿名管道 (Anonymous Pipe)只存在在内存当中父子等亲缘进程间的单向数据生存周期随着亲缘进程的退出而消失在shell当中的 | 就是创建了匿名管道命名管道 (Named Pipe / FIFO)是一种文件存储在文件系统当中任何进程之间都可以使用有名管道进行通信生命周期一直存在在文件系统当中主动删除才会消失// 程序当中创建fifomkfifo(管道文件路径,权限位);# shell当中创建fifomkfifo管道名信号 (Signal)软中断本质进程信息结构体中的int类型的信号位一种异步通知机制用于通知进程发生了某种事件传递信息量小主要用于异常处理或进程控制而非大批量数据交换。不可靠信号1-31信号名称编号默认动作说明常见触发原因SIGHUP1终止(Term)挂断信号通常由控制终端挂起或控制进程退出时发出。SIGINT2终止(Term)来自键盘的中断信号通常通过CtrlC触发。SIGQUIT3终止并转储核心(Core)来自键盘的退出信号通常通过Ctrl\触发会生成core dump文件。SIGILL4终止并转储核心(Core)进程执行了非法指令。SIGTRAP5终止并转储核心(Core)跟踪或断点陷阱常用于调试器。SIGABRT6终止并转储核心(Core)进程调用abort()函数时发出的异常终止信号。SIGIOT6终止并转储核心(Core)IOT陷阱与SIGABRT是等价的。SIGBUS7终止并转储核心(Core)总线错误通常由不正确的内存访问导致。SIGFPE8终止并转储核心(Core)浮点运算异常如除零错误。SIGKILL9终止(Term)强制杀死进程。此信号不可被捕获、阻塞或忽略。SIGUSR110终止(Term)用户自定义信号1可由应用程序自行定义用途。SIGSEGV11终止并转储核心(Core)段错误进程试图访问非法内存地址。SIGUSR212终止(Term)用户自定义信号2可由应用程序自行定义用途。SIGPIPE13终止(Term)管道破裂。进程向一个没有读端的管道或socket写入数据。SIGALRM14终止(Term)由alarm()或setitimer()函数设置的定时器超时。SIGTERM15终止(Term)终止信号是kill命令的默认信号允许进程进行清理后退出。SIGSTKFLT16终止(Term)协处理器栈错误该信号在现代Linux中已很少使用。SIGCHLD17忽略(Ign)子进程状态发生变化如停止或终止时向父进程发送此信号。SIGCONT18继续(Cont)让一个被暂停的进程继续运行。SIGSTOP19停止进程(Stop)暂停进程。此信号不可被捕获、阻塞或忽略。SIGTSTP20停止进程(Stop)来自终端的停止信号通常通过CtrlZ触发。SIGTTIN21停止进程(Stop)后台进程尝试从控制终端读取数据时发送。SIGTTOU22停止进程(Stop)后台进程尝试向控制终端写入数据时发送。SIGURG23忽略(Ign)套接字上出现紧急数据或带外数据。SIGXCPU24终止并转储核心(Core)进程的CPU使用时间超过了其资源限制setrlimit。SIGXFSZ25终止并转储核心(Core)进程创建的文件大小超过了其资源限制setrlimit。SIGVTALRM26终止(Term)虚拟定时器setitimer超时只计算进程用户态CPU时间。SIGPROF27终止(Term)系统资源定时器setitimer超时统计进程用户和内核态CPU时间。SIGWINCH28忽略(Ign)终端窗口大小发生改变。SIGIO/SIGPOLL29终止(Term)文件描述符上可以进行I/O操作异步I/O通知。SIGPWR30终止(Term)电源故障或重启信号System V系统。SIGSYS31终止并转储核心(Core)进程调用了错误的系统调用参数。套接字 (Socket)Unix域套接字 (Unix Domain Socket) 最初由BSD开发是最通用的IPC机制支持不同计算机间的网络通信。其本地通信模式Unix域套接字也常用于单机内高效的双向通信。TCP/UDP—ROS1DDS—ROS2消息队列(Message Queue)在kernel当中的位置ipc/msg.c数据结构链表//System V#includesys/msg.h// 创建---message getintmsgget(key_tkey,intmsgflg);key队列的键值ftok()生成 IPC_PRIVATE msgflg权限和标志 IPC_CREAT创建 IPC_EXCL防止重复创建 权限位(eg0666)返回值成功返回消息队列IDmsqid失败返回-1// 发送方---message sendintmsgsnd(intmsqid,constvoid*msgp,size_tmsgsz,intmsgflg);msqidmsgget()返回的队列ID。 msgp指向消息结构体自定义。 msgsz消息数据部分大小。 msgflg0阻塞 IPC_NOWAIT非阻塞队列满则返回错误 返回值成功返回0失败返回-1。// 接收方---message receivessize_tmsgrcv(intmsqid,void*msgp,size_tmsgsz,longmsgtyp,intmsgflg);msqidmsgget()返回的队列ID。 msgp指向消息结构体自定义需要与发送者一样。 msgsz消息数据部分大小。 msgtyp按类型读取的关键参数。0取队头消息无论类型0取该类型第一条0取绝对值小于等于它的最小类型消息 msgflg0阻塞接收消息 IPC_NOTWAIT消息队列为空时返回错误 MSG_EXCEPT返回队列当中第一个不为msgtype的消息 返回值成功返回实际读取的数据字节数失败返回-1// 控制(包含删除)---message controlintmsgctl(intmsqid,intcmd,structmsqid_ds*buf);cmd控制命令。 IPC_RMID用于删除队列。 IPC_STAT获取队列属性。 IPC_SET设置队列属性。 buf用于存储或设置队列属性的结构体指针。 返回值成功返回0失败返回-1。共享内存(Shared Memory)实现方式多个进程的虚拟内存映射到同一块物理内存区域通信速度最快#include// 获取键值key_t--- file tokenkey_tftok(constchar*pathname,intproj_id);pathname必须是一个已存在且可以访问的文件路径 proj_id项目标识符。它可以用来区分同一个文件生成的多个不同的键值 返回值键值key_t失败返回-1// 创建---shared memory getintshmget(key_tkey,size_tsize,intshmflg);key键值 size共享内存大小字节建议为页大小4096的整数倍 shmflg创建方式 IPC_CREAT不存在则创建存在则返回标识符 IPC_EXCL如果存在则返回错误0666权限 返回值共享内存标识符---句柄shmid失败返回-1// 挂载---shared memory attachvoid*shmat(intshmid,constvoid*shmaddr,intshmflg);shmid共享内存标识符 shmaddr通常设为NULL由系统自动选择地址 shmflg共享内存读写权限0可读写 SHM_RDONLY只读 返回值共享内存起始地址指针失败返回(void*)-1// 分离---shared memory detachintshmdt(constvoid*shmaddr);shmaddr要断开的内存的地址 返回值成功返回0失败返回-1// 控制包括删除---shared memory controlintshmctl(intshmid,intcmd,structshmid_ds*buf);shmid共享内存标识符 cmd控制命令 IPC_RMID删除 IPC_STAT获取状态 IPC_SET设置共享内存状态信息 buf保存状态信息的数据结构 返回值成功返回0失败返回-1ROS2当中的零拷贝就是共享内存信号量(Semaphore)二值信号量计数信号量// 创建---semaphore getintsemget(key_tkey,intnsems,intsemflg);key信号量标识**不同进程可以使用同一个信号量**nsems信号量集中信号量的个数 semflg信号量集的访问权限 IPC_CREAT|0666返回值信号量标识符---句柄semid失败返回-1// 控制信号量集---semaphore controlintsemctl(intsemid,intsemnum,intcmd,...);semid信号量标识符 semnum信号量在集中的索引 cmd控制命令 SETVAL设置值 IPC_STAT获取信号量集的状态信息。 IPC_RMID删除信号量集。 GETVAL获取信号量的当前值 GETPID获取最后一个对信号量执行wait操作的进程的PID。 GETNCNT获取等待信号量值大于0的进程数。 GETZCNT获取等待信号量值等于0的进程数。..可选参数其类型和含义取决于cmd参数的值。 返回值取决于cmd失败返回-1// 使用P/V操作---semaphore operationintsemop(intsemid,structsembuf*sops,unsignednsops);semid信号量标识符 sops操作数组 包含 sem_num信号量索引、sem_op操作值、sem_flg标志// nsops操作数组的元素个数// 返回值成功返回0失败返回 -1structsembuf{unsignedshortsem_num;// 信号量索引shortsem_op;// 操作值shortsem_fig;// 标志}System V IPC这是ATT贝尔实验室发展的一套经典IPC机制适用于单机内部通信。共享内存是最快的IPC方式而信号量则常作为同步工具配合使用。POSIX IPC为提升System V IPC的可移植性和灵活性而设计的标准化接口。它提供了更现代化的API并且新增了线程同步原语如互斥量、条件变量。POSIX消息队列 (mqueue.h)POSIX 消息队列相比 System V 消息队列提供了基于优先级的消息传递、异步通知机制信号或线程、以及更简洁的文件描述符式 API。编译时需链接-lrt。// 打开/创建消息队列mqd_tmq_open(constchar*name,intoflag,.../* mode_t mode, struct mq_attr *attr */);name消息队列名称必须以斜杠开头如/myqueue且不含其他斜杠 oflag访问标志 O_RDONLY只读 O_WRONLY只写 O_RDWR读写 O_CREAT不存在则创建需提供 mode 和 attr 参数 O_EXCL与 O_CREAT 连用队列已存在则失败 O_NONBLOCK非阻塞模式 mode创建权限如0666仅在 O_CREAT 时使用 attr队列属性NULL表示使用系统默认值structmq_attr{longmq_flags;// 队列标志0 或 O_NONBLOCKlongmq_maxmsg;// 队列最大消息数longmq_msgsize;// 单条消息最大字节数longmq_curmsgs;// 当前队列中消息数只读};返回值成功返回消息队列描述符mqd_t失败返回(mqd_t)-1并设置 errno// 发送消息intmq_send(mqd_tmqdes,constchar*msg_ptr,size_tmsg_len,unsignedintmsg_prio);mqdesmq_open()返回的队列描述符 msg_ptr指向消息数据的指针 msg_len消息长度字节数不能超过 mq_msgsize msg_prio消息优先级值越大优先级越高队列按优先级从高到低排序 返回值成功返回0失败返回-1并设置 errno 说明若队列满且未设置 O_NONBLOCK调用线程将阻塞// 带超时发送消息intmq_timedsend(mqd_tmqdes,constchar*msg_ptr,size_tmsg_len,unsignedintmsg_prio,conststructtimespec*abs_timeout);abs_timeout绝对超时时间基于 CLOCK_REALTIME 返回值成功返回0超时返回-1且 errno 为 ETIMEDOUT// 接收消息ssize_tmq_receive(mqd_tmqdes,char*msg_ptr,size_tmsg_len,unsignedint*msg_prio);mqdesmq_open()返回的队列描述符 msg_ptr存储接收消息的缓冲区 msg_len缓冲区大小必须mq_msgsize msg_prio若非NULL存储接收消息的优先级 返回值成功返回接收到的字节数失败返回-1并设置 errno 说明始终接收队列中优先级最高的消息// 带超时接收消息ssize_tmq_timedreceive(mqd_tmqdes,char*msg_ptr,size_tmsg_len,unsignedint*msg_prio,conststructtimespec*abs_timeout);abs_timeout绝对超时时间基于 CLOCK_REALTIME 返回值成功返回接收到的字节数超时返回-1且 errno 为 ETIMEDOUT// 注册异步通知intmq_notify(mqd_tmqdes,conststructsigevent*notification);mqdesmq_open()返回的队列描述符 notification通知方式structsigevent{intsigev_notify;// 通知方式SIGEV_NONE不通知 SIGEV_SIGNAL发送信号 SIGEV_THREAD启动线程intsigev_signo;// 信号编号SIGEV_SIGNAL 时unionsigval sigev_value;// 信号附带数据void(*sigev_notify_function)(unionsigval);// 线程函数SIGEV_THREAD 时pthread_attr_t*sigev_notify_attributes;// 线程属性};返回值成功返回0失败返回-1并设置 errno 说明每个队列同一时间只能有一个进程注册通知 当队列从空变为非空时系统向注册进程发送通知 通知发生后注册自动解除需重新注册// 获取队列属性intmq_getattr(mqd_tmqdes,structmq_attr*attr);mqdesmq_open()返回的队列描述符 attr存储属性的结构体指针 返回值成功返回0失败返回-1并设置 errno// 设置队列属性intmq_setattr(mqd_tmqdes,conststructmq_attr*newattr,structmq_attr*oldattr);mqdesmq_open()返回的队列描述符 newattr新属性仅 mq_flags 中的 O_NONBLOCK 标志可修改 oldattr保存修改前的属性不需要时设为NULL返回值成功返回0失败返回-1并设置 errno// 关闭消息队列intmq_close(mqd_tmqdes);mqdesmq_open()返回的队列描述符 返回值成功返回0失败返回-1并设置 errno 说明关闭描述符但不删除队列。进程终止时自动关闭所有已打开的队列// 删除消息队列intmq_unlink(constchar*name);name消息队列名称 返回值成功返回0失败返回-1并设置 errno 说明删除队列名称。若仍有进程打开该队列队列在所有进程关闭后才被销毁 类似文件系统的 unlink 机制POSIX信号量 (semaphore.h)POSIX 信号量相比 System V 信号量API 更简洁分为有名信号量可用于不相关进程间和无名信号量基于内存用于线程或亲缘进程间。编译时需链接-pthread无名信号量或-lrt部分系统有名信号量。有名信号量// 打开/创建有名信号量sem_t*sem_open(constchar*name,intoflag,.../* mode_t mode, unsigned int value */);name信号量名称必须以斜杠开头如/mysem oflag访问标志 O_CREAT不存在则创建需提供 mode 和 value 参数 O_EXCL与 O_CREAT 连用信号量已存在则失败 mode创建权限如0666仅在 O_CREAT 时使用 value信号量初始值 返回值成功返回信号量指针失败返回 SEM_FAILED 并设置 errno// 关闭有名信号量intsem_close(sem_t*sem);semsem_open()返回的信号量指针 返回值成功返回0失败返回-1并设置 errno 说明关闭信号量进程终止时自动关闭所有已打开的信号量// 删除有名信号量intsem_unlink(constchar*name);name信号量名称 返回值成功返回0失败返回-1并设置 errno 说明删除信号量名称。若仍有进程打开信号量在所有进程关闭后才被销毁无名信号量// 初始化无名信号量intsem_init(sem_t*sem,intpshared,unsignedintvalue);sem指向信号量对象的指针 pshared共享属性0仅在同一个进程的线程间共享 非0可在进程间共享信号量需位于共享内存区域 value信号量初始值 返回值成功返回0失败返回-1并设置 errno// 销毁无名信号量intsem_destroy(sem_t*sem);sem指向信号量对象的指针 返回值成功返回0失败返回-1并设置 errno 说明销毁前确保没有线程在等待该信号量 仅对 sem_init 初始化的信号量使用不可用于有名信号量通用操作有名/无名信号量通用// P操作 - 等待信号量阻塞intsem_wait(sem_t*sem);sem指向信号量对象的指针 返回值成功返回0失败返回-1并设置 errno 说明将信号量值减1。若值已为0调用线程阻塞直到值大于0// P操作 - 尝试等待信号量非阻塞intsem_trywait(sem_t*sem);sem指向信号量对象的指针 返回值成功返回0失败返回-1且 errno 为 EAGAIN信号量值为0// P操作 - 带超时等待信号量intsem_timedwait(sem_t*sem,conststructtimespec*abs_timeout);sem指向信号量对象的指针 abs_timeout绝对超时时间基于 CLOCK_REALTIME 返回值成功返回0超时返回-1且 errno 为 ETIMEDOUT// V操作 - 释放信号量intsem_post(sem_t*sem);sem指向信号量对象的指针 返回值成功返回0失败返回-1并设置 errno 说明将信号量值加1若有线程在等待则唤醒其中一个// 获取信号量当前值intsem_getvalue(sem_t*sem,int*sval);sem指向信号量对象的指针 sval存储信号量当前值的指针 返回值成功返回0失败返回-1并设置 errno 说明返回值为调用瞬间的快照可能立即过时仅作调试/监控用途POSIX共享内存 (sys/mman.h)POSIX 共享内存通过内存映射文件memfd实现使用文件描述符操作比 System V 共享内存的 shmget/shmat 接口更统一。编译时需链接-lrt部分系统还需-lpthread。// 创建/打开共享内存对象intshm_open(constchar*name,intoflag,mode_tmode);name共享内存对象名称必须以斜杠开头如/myshm且不含其他斜杠 oflag访问标志 O_RDONLY只读 O_RDWR读写 O_CREAT不存在则创建 O_EXCL与 O_CREAT 连用对象已存在则失败 O_TRUNC若对象已存在则将其截断为0长度 mode创建权限如0666仅在 O_CREAT 时使用 返回值成功返回文件描述符失败返回-1并设置 errno 说明shm_open 仅创建对象大小初始为0需用 ftruncate 设置大小// 设置共享内存大小intftruncate(intfd,off_tlength);fdshm_open()返回的文件描述符 length共享内存大小字节建议为页大小4096的整数倍 返回值成功返回0失败返回-1并设置 errno 说明新创建的共享内存对象大小为0必须调用 ftruncate 设置大小后才能映射// 内存映射void*mmap(void*addr,size_tlength,intprot,intflags,intfd,off_toffset);addr映射起始地址通常设为NULL由系统选择 length映射长度字节 prot内存保护标志 PROT_READ可读 PROT_WRITE可写 PROT_EXEC可执行 PROT_NONE不可访问 flags映射标志 MAP_SHARED共享映射修改对其他进程可见且同步到底层对象 MAP_PRIVATE私有映射修改不反映到底层对象写时复制 MAP_ANONYMOUS匿名映射不基于文件fd 设为-1MAP_FIXED强制映射到 addr 指定的地址不推荐 fdshm_open()返回的文件描述符MAP_ANONYMOUS 时设为-1 offset文件偏移量必须为页大小的整数倍通常设为0返回值成功返回映射区域的指针失败返回MAP_FAILED((void*)-1)并设置 errno// 解除映射intmunmap(void*addr,size_tlength);addrmmap()返回的映射地址 length映射长度 返回值成功返回0失败返回-1并设置 errno 说明进程终止时自动解除所有映射// 同步映射区域到磁盘intmsync(void*addr,size_tlength,intflags);addr映射地址 length同步长度 flags同步方式 MS_SYNC同步等待写入完成 MS_ASYNC异步发起写入 MS_INVALIDATE使缓存失效使后续访问重新从磁盘读取 返回值成功返回0失败返回-1并设置 errno// 关闭共享内存对象intclose(intfd);fdshm_open()返回的文件描述符 返回值成功返回0失败返回-1并设置 errno 说明关闭文件描述符但不删除共享内存对象也不解除已有的映射// 删除共享内存对象intshm_unlink(constchar*name);name共享内存对象名称 返回值成功返回0失败返回-1并设置 errno 说明删除共享内存对象名称。若仍有进程映射该对象对象在所有映射解除后才被销毁 类似文件系统的 unlink 机制
返回列表