1. 进程间通信(IPC)
进程间通信(IPC)是指在不同进程之间交换数据或信息的机制。常见的 IPC 方法包括:
1.1 管道(Pipe)
无名管道(Anonymous Pipe):
只能用于具有亲缘关系的进程间通信(如父子进程)。
使用
pipe()
系统调用创建。特点:
读操作:如果管道中有数据,则直接读取;如果没有数据,会阻塞等待。
写操作:如果管道中有读端且未满,则直接写入;如果管道已满,会阻塞等待。
如果管道中没有读端,写入数据会导致管道破裂(
SIGPIPE
信号)。
有名管道(Named Pipe/FIFO):
可以用于任意两个进程之间的通信。
使用
mkfifo()
系统调用创建。特点:
必须读写两端同时打开,才能继续执行;否则会阻塞等待。
1.2 信号(Signal)
定义:
提供一种内核层与用户层之间的通知机制。
信号是一种软件中断,用于通知进程某些事件的发生。
信号类型:
SIGINT
(2):中断信号(如 Ctrl+C)。SIGQUIT
(3):退出信号(如 Ctrl+\)。SIGSEGV
(11):段错误。SIGPIPE
(13):管道破裂。SIGALRM
(14):定时信号。SIGCHLD
(17):子进程结束。SIGSTOP
(19):停止进程。SIGTSTP
(20):挂起进程(如 Ctrl+Z)。SIGIO
(29):异步 I/O 信号。
对信号的处理方式:
忽略:信号来了,不处理该信号。
缺省:信号来了,按照默认的方式处理信号。
捕捉:信号来了,按照指定的方式处理信号。
注意:
SIGKILL
(9)和SIGSTOP
(19)不能被忽略或捕捉。
函数接口:
typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
功能:修改信号的处理方式。
参数:
signum
:信号编号。handler
:信号处理方式(SIG_IGN
忽略,SIG_DFL
缺省)。
返回值:
成功返回之前的信号处理函数。
失败返回
SIG_ERR
。
1.3 消息队列(Message Queue)
提供一种在进程间传递消息的机制。
消息队列允许一个或多个进程向队列中写入消息,同时允许一个或多个进程读取这些消息。
1.4 共享内存(Shared Memory)
允许多个进程共享同一块内存区域。
提供高效的进程间通信,但需要同步机制(如互斥锁)来避免数据竞争。
1.5 信号量(Semaphore)
提供一种同步机制,用于控制对共享资源的访问。
函数接口:
int sem_init(sem_t *sem, int pshared, unsigned int value); int sem_destroy(sem_t *sem); int sem_wait(sem_t *sem); int sem_post(sem_t *sem);
sem_init
:初始化信号量。sem_destroy
:销毁信号量。sem_wait
:申请信号量资源(资源数 - 1)。sem_post
:释放信号量资源(资源数 + 1)。
1.6 套接字(Socket)
提供一种在不同主机上的进程之间进行通信的机制。
支持多种协议(如 TCP/IP、UDP/IP)。
2. 管道的详细说明
2.1 无名管道
创建:
int pipe(int pipefd[2]);
功能:创建操作管道的两个文件描述符。
参数:
pipefd[0]
:读文件描述符。pipefd[1]
:写文件描述符。
返回值:
成功返回 0。
失败返回 -1。
2.2 有名管道
创建:
int mkfifo(const char *pathname, mode_t mode);
功能:创建管道文件。
参数:
pathname
:管道文件名。mode
:权限。
返回值:
成功返回 0。
失败返回 -1。
3. 信号的详细说明
3.1 信号处理
信号列表:
使用
kill -l
命令查看所有信号。示例:
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
信号处理方式:
忽略:
SIG_IGN
。缺省:
SIG_DFL
。捕捉:自定义处理函数。
示例代码:
#include <stdio.h> #include <signal.h> void handle_sigint(int sig) { printf("SIGINT signal received\n"); } void handle_sigquit(int sig) { printf("SIGQUIT signal received\n"); } int main() { signal(SIGINT, handle_sigint); // 捕捉 SIGINT signal(SIGQUIT, handle_sigquit); // 捕捉 SIGQUIT printf("Press Ctrl+C or Ctrl+\\ to test signals\n"); while (1) { // 等待信号 } return 0; }
3.2 定时信号
alarm()
:unsigned int alarm(unsigned int seconds);
功能:定时
seconds
秒后给当前进程发送SIGALRM
信号。参数:
seconds
:秒数。
返回值:
成功返回之前定时剩余的秒数。
如果之前没有定时返回 0。
3.3 发送信号
kill()
:int kill(pid_t pid, int sig);
功能:向
pid
对应的进程发送sig
信号。参数:
pid
:目标进程的 PID。sig
:信号编号。
返回值:
成功返回 0。
失败返回 -1。
4. 总结
管道:
无名管道:用于具有亲缘关系的进程间通信。
有名管道:用于任意两个进程之间的通信。
信号:
提供内核层与用户层之间的通知机制。
可以通过
signal()
设置信号处理方式。
消息队列:
提供进程间传递消息的机制。
共享内存:
提供高效的进程间通信,但需要同步机制。
信号量:
提供同步机制,用于控制对共享资源的访问。
套接字:
提供不同主机上的进程之间进行通信的机制