好课优选告诉您AI 漫剧绘画提示词可以这样写
2026/7/7 8:21:08
在 Linux 系统中,进程间通信(IPC)是实现多进程协作的核心能力,其中信号通信和共享内存是两种高频使用的通信方式:
信号是 Linux 内核提供的异步通信机制,本质是 “通知机制”,用于处理系统中的 “随机事件”(如进程暂停、唤醒、终止、自定义事件等),核心特点:
kill命令、系统调用、硬件异常等);handle2);c
运行
#include <signal.h> int kill(pid_t pid, int sig);pid:接收信号的进程 PID;sig:信号编号(可通过kill -l查看所有信号编号);示例:向 PID 为 1000 的进程发送 SIGCONT(唤醒)信号
c
运行
kill(1000, 18); // 18是SIGCONT的默认编号,等价于kill -CONT 1000c
运行
#include <signal.h> // 函数原型(简化版) sighandler_t signal(int signum, sighandler_t handler);signum:要捕获的信号编号;handler:信号处理方式,支持 3 种:SIG_DFL:使用系统默认处理行为;SIG_IGN:忽略该信号;void myhandle(int num),接收信号编号作为参数;SIG_ERR。示例:自定义 SIGCONT 信号的处理函数
c
运行
void myhandle(int num) { printf("捕获到信号%d,进程被唤醒\n", num); } // 注册信号处理函数 signal(SIGCONT, myhandle);kill -l;man 7 signal。共享内存是 System V 标准提供的 IPC 方式,核心是让多个进程映射同一块物理内存到自己的地址空间,实现数据直接互通。
graph LR A[生成唯一Key值:ftok()] --> B[申请共享内存:shmget()] B --> C[映射到进程地址空间:shmat()] C --> D[读写共享内存:memcpy/strcpy] D --> E[撤销映射:shmdt()] E --> F[删除共享内存:shmctl()]c
运行
#include <sys/ipc.h> key_t ftok(const char *pathname, int proj_id);pathname:任意文件路径(需保证文件不被删除 / 重建,否则 Key 值会变化);proj_id:整型标识(通常用 ASCII 单字符,如'!');示例:
c
运行
key_t key = ftok("./", '!'); // 基于当前目录生成Key值c
运行
#include <sys/shm.h> int shmget(key_t key, size_t size, int shmflg);key:ftok 生成的唯一 Key 值;size:共享内存大小(字节,建议为 4096 的整数倍);shmflg:权限 + 创建标识,常用IPC_CREAT | 0666(不存在则创建,权限为 666);示例:
c
运行
int shmid = shmget(key, 4096, IPC_CREAT | 0666);c
运行
#include <sys/shm.h> void *shmat(int shmid, const void *shmaddr, int shmflg);shmid:shmget 返回的共享内存 ID;shmaddr:指定映射地址,NULL 表示由系统自动分配;shmflg:访问权限,0 表示可读写,SHM_RDONLY表示只读;(void*)-1。示例:
c
运行
void *p = shmat(shmid, NULL, 0); // 映射为可读写共享内存映射后可直接当作普通内存使用,支持字符串 / 二进制数据操作:
c
运行
// 写入字符串 strcpy((char*)p, "共享内存测试数据"); // 读取字符串 printf("共享内存内容:%s\n", (char*)p); // 二进制数据读写(如结构体) memcpy(p, &data, sizeof(data));c
运行
#include <sys/shm.h> int shmdt(const void *shmaddr);示例:
c
运行
shmdt(p); // 撤销映射c
运行
#include <sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf);shmid:共享内存 ID;cmd:操作指令,IPC_RMID表示删除;buf:NULL 表示仅删除,无需获取属性;示例:
c
运行
shmctl(shmid, IPC_RMID, NULL); // 彻底删除共享内存ipcs -a;ipcrm -m 共享内存ID。管道(无名pipe/ 有名mkfifo)也是常用 IPC 方式,但与共享内存差异显著:
| 特性 | 共享内存 | 管道(无名 / 有名) |
|---|---|---|
| 读写权限 | 双方均可读写 | 无名管道:固定读端 / 写端;有名管道:双向但需同步 |
| 阻塞特性 | 无读 / 写阻塞 | 读阻塞(无数据)、写阻塞(缓冲区满) |
| 同步机制 | 无,需搭配信号 / 信号量 | 自带同步(阻塞机制) |
| 数据存储 | 内存中,不删除则一直存在 | 内核缓冲区,读取后数据消失 |
| 数据拷贝 | 无拷贝(直接操作内存) | 需内核态 / 用户态拷贝 |
| 易用性 | 需手动管理映射 / 删除 | 可当作文件操作,更简单 |
c
运行
#include <unistd.h> int pipe(int pipefd[2]);pipefd[0]为读端,pipefd[1]为写端;c
运行
#include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode);pathname:管道文件的路径 + 名称;mode:文件权限(8 进制,如 0666);c
运行
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> void myhandle(int num) { printf("进程A捕获到信号%d,被唤醒\n", num); } int main() { // 1. 生成Key值 key_t key = ftok("./", '!'); if (key == -1) { perror("ftok"); return 1; } // 2. 申请共享内存 int shmid = shmget(key, 4096, IPC_CREAT | 0666); if (shmid == -1) { perror("shmget"); return 1; } // 3. 映射共享内存 void *p = shmat(shmid, NULL, 0); if (p == (void*)-1) { perror("shmat"); return 1; } // 4. 写入数据 strcpy((char*)p, "Hello, 共享内存+信号通信"); printf("进程A PID:%d,已写入数据到共享内存\n", getpid()); // 5. 注册SIGCONT信号处理函数 signal(SIGCONT, myhandle); // 6. 等待信号唤醒 printf("进程A进入阻塞,等待信号...\n"); pause(); // 7. 撤销映射 shmdt(p); // 8. 删除共享内存(可选) shmctl(shmid, IPC_RMID, NULL); return 0; }c
运行
#include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(int argc, char *argv[]) { if (argc < 2) { printf("用法:%s <进程A的PID>\n", argv[0]); return 1; } pid_t pid_a = atoi(argv[1]); // 1. 生成相同的Key值 key_t key = ftok("./", '!'); if (key == -1) { perror("ftok"); return 1; } // 2. 获取共享内存 int shmid = shmget(key, 4096, 0666); if (shmid == -1) { perror("shmget"); return 1; } // 3. 映射共享内存 void *p = shmat(shmid, NULL, 0); if (p == (void*)-1) { perror("shmat"); return 1; } // 4. 读取共享内存数据 printf("进程B读取到共享内存数据:%s\n", (char*)p); // 5. 发送SIGCONT信号唤醒进程A kill(pid_a, 18); printf("进程B已向进程A发送唤醒信号\n"); // 6. 撤销映射 shmdt(p); return 0; }gcc shm_signal_a.c -o a.out,运行:./a.out(记录进程 A 的 PID);gcc shm_signal_b.c -o b.out,运行:./b.out <进程A的PID>;kill发送信号、signal捕获信号,适用于事件触发、进程唤醒等场景;