|

3rqolratvad64088525943.gif
0 x8 k' E2 b% {6 i点击上方蓝色字体,关注我们2 f T# N" \3 H% l
' ?2 L* T4 X* m6 \
1.1、UNIX IPC
" f" n; F! u0 L( |$ nUNIX 传统的 IPC 机制包括管道、FIFO 和信号,这些机制最早由 UNIX 系统引入,适用于简单的单机进程间通信。
/ s: |8 x, M' u( J/ {+ J管道(Pipe):
M( {% p. [- o7 |# y0 ^一种单向、半双工的通信机制,通常用于父子进程间的数据传递。
; n' Q& \; d# B父进程可以写入数据,子进程可以读取。FIFO(命名管道):8 |9 R( y, S& s) n" @! n6 D9 f
类似于管道,但通过文件系统实现,任何进程都可以通过路径访问该管道,实现双向通信。信号(Signal):
7 m) C% Y7 x9 q ]1 ~" o信号是一种用于进程间异步通知的机制,可以用于进程之间的简单通信或事件通知,例如 SIGINT(Ctrl+C 发送的中断信号)。
e3 y+ n. v b' {
4 a- V$ b1 L1 M1.2、System V IPC+ m6 w( Y8 H8 ~9 |! l
System V IPC 是 UNIX 的增强版本,主要包括信号量、消息队列和共享内存,适合需要更复杂的进程同步与数据共享的场景。/ v8 @* f8 \# s2 R; u
信号量(Semaphore):; q1 v/ V4 q1 f" F, \% L, u1 t0 Z
用于进程间的同步,通常用于控制对共享资源的访问。
" r( _& x; K' i6 N) s- \信号量用于防止多个进程同时访问同一资源,避免资源争用问题。消息队列(Message Queue):
; Q) T$ H% G( p1 ^& p允许进程以消息的形式发送和接收数据。
! {! b& C4 a- U) b3 ^8 s+ Q {消息队列是一种先进先出(FIFO)的结构,支持不同类型的消息,使得进程可以基于消息类型进行处理。共享内存(Shared Memory):& w' x$ f' S7 u/ q' P6 ^; N
进程之间共享同一块内存区域,允许它们直接读写数据。
5 _3 G: ?9 E" ]这是最有效的 IPC 方式,因为数据不需要在进程之间复制。
4 M3 W; y, Y0 T( T7 X
7 ~# O. a' h+ [$ q- K# o x$ B, H1.3、POSIX IPC
1 ]" Y7 m2 T; E$ H; [. o' X: zPOSIX IPC 是 System V IPC 的改进版本,旨在解决 System V IPC 在灵活性和可移植性上的一些不足。
! K' _; ?+ w, G" k3 x/ ^8 y; M6 G
+ |! L& [% E! N3 x: Z8 GPOSIX 标准为 UNIX 系统间的兼容性提供了统一的接口,使得程序可以更方便地在不同的 UNIX 系统间移植。
1 G% W* _9 g* T$ v+ F5 N- GPOSIX 信号量:
9 q( B% u% L% o K, X# F与 System V 信号量类似,用于进程同步,但提供了更灵活的接口和更强的实时性支持。POSIX 消息队列:
( ]) @! l+ s" C" M: h5 z" q7 l改进了 System V 消息队列,允许指定消息的优先级,并提供更简单的接口。POSIX 共享内存:( g+ w6 @) b5 H' U) |6 y$ x. ~
与 System V 共享内存类似,但具有更好的兼容性和可移植性,接口设计更加现代化。
% q6 I5 ^% [! I @: D6 J
- h+ H8 U: A8 R5 Q" ~1.4、套接字(Socket)通信7 J8 I$ D6 m+ M- H& z% }1 Z
套接字是一种既可以用于本地进程间通信,也可以用于网络通信的机制,支持双向数据传输。" R$ Y: ]4 q5 w6 D
) D) _2 v+ v+ s9 P, H) l3 h! a基于套接字的 IPC 可以实现非常灵活的通信模式,例如客户端-服务器架构,适合在多台计算机之间传递数据。! [& \1 F9 ]$ e9 e6 S6 M
. ]( n) @. r: R; F$ r6 Z
各类 IPC 机制的对比和应用场景:
( Z/ t3 J! i4 m+ j
; A; O8 L2 q( \9 K) Q
bsbbcgpudkr64088526043.png
d* Q4 p: `5 [; x& q' T9 C
) p1 S7 q; `; s$ f9 p/ O; ^2
8 {/ i* E" b' U: \& |管道(Pipe)
/ M: o( H% F" b" ]$ f& }$ N& K# f管道是一种半双工(单向)的通信方式,通常用于父子进程之间的通信。一个进程可以向管道写入数据,另一个进程从管道读取数据。
) ]' Q Q. S& J
. Q4 S4 M$ t& v8 o6 ?Linux 提供了无名管道和命名管道两种类型。
/ x" F: S7 G y ~9 b2 S0 ]无名管道(Anonymous Pipe):: u4 ]# B9 j8 s2 ^
只能在具有亲缘关系的进程间使用,比如父进程和子进程。命名管道(Named Pipe 或 FIFO):
" h0 ?1 n2 u; ^) N* N/ Y* B( j( X通过文件系统中的路径来创建,任意进程都可以访问。
! v9 X& }, t1 f5 }; F& @& p! D
3 M( y u. H' b! w5 `2 M2 v( M
0 [+ y3 X7 ~; @) i+ M* L: v示例:
3 g) E/ |7 j4 J7 n3 N: v: t' e$ x( d
int main() { int fd[2]; pipe(fd); // 创建无名管道) [) r5 w) e+ r: p# c) u
if (fork() == 0) { // 子进程 close(fd[0]); // 关闭读取端 write(fd[1], "Hello, parent!", 15); close(fd[1]); } else { // 父进程 char buffer[20]; close(fd[1]); // 关闭写入端 read(fd[0], buffer, sizeof(buffer)); printf("Received: %s
# N; K! X/ Y% }' |", buffer); close(fd[0]); } return 0;}- z( \1 F# _! q2 P
37 o5 u. o& l% i' N% s* p; G% E
消息队列(Message Queue); v; @1 l& Q1 H5 G, l+ A4 ]% K% y! H
消息队列是一种先进先出的队列,允许进程以消息的形式发送和接收数据。0 Y ]5 Y. V0 U9 c6 J, G3 A& C
# {$ @- d% T( P( n; N( |! |4 M0 [
消息队列可以支持多种类型的消息,通过消息类型实现多种目的的通信。0 h" j; M( ~ j: I( S& b' t
+ Y6 J9 X7 a' J
示例:进程A可以向队列发送一个带有特定类型的消息,而进程B可以根据消息类型进行处理。
5 V# s! [' a$ {. `4 c6 Q. T
* |! N1 m8 X$ [9 ?# v4 bstruct msgbuf { long mtype; char mtext[100];};
r& y* g/ R! _. B8 b7 M" |- Mint main() { key_t key = ftok("msgqueue", 65); int msgid = msgget(key, 0666 | IPC_CREAT); struct msgbuf message;6 a `% [6 p1 }3 h2 k9 l8 e
message.mtype = 1; // 消息类型 snprintf(message.mtext, sizeof(message.mtext), "Hello Message Queue"); msgsnd(msgid, &message, sizeof(message.mtext), 0);+ E* ~4 P: h" P% s8 ?4 f1 I A6 y/ w7 h
return 0;}
4 X( J7 M' y0 x; |3 E0 [46 j& T8 ~/ X# H* t) P9 t6 a
共享内存(Shared Memory)
2 R" a, Y3 D3 |* K$ j7 c共享内存是最快的 IPC 机制之一,因为进程之间直接访问同一块内存区域,而不需要拷贝数据。
) ^# T- W7 X/ M2 t( S# ~
! k1 L) f4 H& b- G. l+ A% J; K; R通常使用 shmget()、shmat() 和 shmdt() 函数进行共享内存的创建和访问。
% ]+ D% J$ E, q( r1 \" [: t" N0 X
[6 ^2 v/ x8 h示例:
3 `! e& K& c; j: V5 i7 B
3 r2 p0 d G/ m' g% I1 n9 i* o: jint main() { key_t key = ftok("shmfile",65); int shmid = shmget(key, 1024, 0666|IPC_CREAT); char *str = (char*) shmat(shmid, (void*)0, 0);
$ c/ _% n! V0 o$ h strcpy(str, "Hello Shared Memory");
: |- e* H2 i0 Q# z2 }& L4 { printf("Data written in memory: %s
6 [( @' `! i4 m( C", str); shmdt(str);
8 m0 Z4 ~/ A! _, V' A/ i% R, I return 0;}
& I* T# m; c6 g. F) B5
/ k* z, K) T5 z" i$ r* a) w信号量(Semaphore)1 Q$ O1 C4 h# I( `% \' |+ R3 a
信号量是一种用于进程同步的机制,通常用于控制多个进程对共享资源的访问。% ]: e% K$ d2 n3 ?
& z+ ]6 U- _' I* k* m3 E0 ^+ N
嵌入式系统中,信号量通常用来避免多个进程同时访问同一资源,防止数据竞争。
$ z; m: y9 s3 {0 r9 d, a$ A
5 _3 H; f$ }0 z% x4 \5 c z示例:信号量可以通过 semget() 和 semop() 函数来操作,用于锁定或解锁资源。% E/ E3 {0 C% G
1 |/ x" n5 k; R# v; u- h9 v4 Y. B1 `int main() { key_t key = ftok("semfile",65); int semid = semget(key, 1, 0666 | IPC_CREAT); struct sembuf sem_lock = {0, -1, 0}; // 减1操作 struct sembuf sem_unlock = {0, 1, 0}; // 加1操作( ~% j8 c# Z4 R# ~$ }% M
semop(semid, &sem_lock, 1); // 上锁 printf("Critical section3 l) a0 \5 r, T: s2 k
"); semop(semid, &sem_unlock, 1); // 解锁
8 i6 \& S8 ~0 U# B( M return 0;}5 G& O3 ?# Y- L& I
60 U' M5 }/ F* Z# t
套接字(Socket)3 X, X% r( E% y* [$ [& G
套接字不仅支持本地进程间通信,还可以用于网络通信。) K' ]( j) L/ u( B! r: O
* [* U. ^9 h; T% @基于套接字的 IPC 支持双向通信,比较灵活,适合嵌入式系统中进程之间需要频繁且复杂的数据交互的情况。2 v+ x% |6 h j% E
. g6 C1 V+ c4 F示例:
$ `1 f) a) Z, O- S" `
! C: w+ `9 G) t& O7 Sint main() { int sv[2]; socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
0 g, v, y' Z; G" { if (fork() == 0) { // 子进程 close(sv[0]); write(sv[1], "Hello from child", 16); close(sv[1]); } else { // 父进程 char buffer[20]; close(sv[1]); read(sv[0], buffer, sizeof(buffer)); printf("Received: %s
k" O6 r/ X3 @& q& a- A", buffer); close(sv[0]); } return 0;}7 t4 L# G5 O4 T) [# d0 R
7
) I. D+ ]& b) l信号(Signal)
3 k9 l+ U @8 N0 d! M) r9 E* V6 B信号是用来通知进程发生某种事件的机制。进程可以捕获、忽略或处理信号,典型的信号包括 SIGINT(中断信号)和 SIGKILL(杀死进程信号)。
; }1 C1 _9 L3 C% D" B$ h" `2 B; E+ u4 p/ A: u( a' E U
示例:处理 SIGINT 信号(Ctrl+C)。
+ H8 k5 d7 e* x. Q& H6 N
9 k( ]* A% ]/ U/ Wvoid sigint_handler(int sig) { printf("Caught signal %d
0 ~1 @% u9 {. a5 ~", sig);}& w' T4 S" B' e5 D4 N! w3 g
int main() { signal(SIGINT, sigint_handler); while (1) { printf("Running...
Z" \- s( @$ r' g. n, o"); sleep(1); } return 0;}
/ x/ s: [8 u/ _6 J$ C7 E进程间通信的机制多种多样,选择合适的方式取决于应用场景的需求。
* p1 N( Y5 \6 ~" t5 L
pxe3tci4tfg64088526143.jpg
6 a0 [! y; D# |! T) ^% X4 B' I
qjqlous0j2064088526243.gif
! _$ U2 Y& p( ~% }% @9 d点击阅读原文,更精彩~ |
|