|

3rqolratvad64088525943.gif
4 X; z0 v3 ~7 Q, T4 n点击上方蓝色字体,关注我们. @8 O5 `( u4 n% Y, l( k3 L
$ n" [7 N& M+ K8 X, J" M" x$ ~1.1、UNIX IPC
( [) Y/ r' F- u7 c! n% x YUNIX 传统的 IPC 机制包括管道、FIFO 和信号,这些机制最早由 UNIX 系统引入,适用于简单的单机进程间通信。6 w0 ?1 h& S" ^5 Y* B4 R
管道(Pipe):
0 Y6 c5 N/ y7 u3 o一种单向、半双工的通信机制,通常用于父子进程间的数据传递。7 f+ l/ T5 t5 z! w! p5 o& O
父进程可以写入数据,子进程可以读取。FIFO(命名管道):
7 @' n. ?0 i H& x! u( ~) ?+ Z; D( ]类似于管道,但通过文件系统实现,任何进程都可以通过路径访问该管道,实现双向通信。信号(Signal):
1 i" b1 z& Q3 A8 ?1 R. K信号是一种用于进程间异步通知的机制,可以用于进程之间的简单通信或事件通知,例如 SIGINT(Ctrl+C 发送的中断信号)。* |% k/ h3 u# P/ J
3 t: ^1 J5 _! Y1.2、System V IPC
: ?0 | k9 D1 N+ Z- P5 mSystem V IPC 是 UNIX 的增强版本,主要包括信号量、消息队列和共享内存,适合需要更复杂的进程同步与数据共享的场景。5 u* L5 c, g( {5 D" K
信号量(Semaphore):
# l. [4 I# x. V用于进程间的同步,通常用于控制对共享资源的访问。) l$ z9 i+ s8 n0 C
信号量用于防止多个进程同时访问同一资源,避免资源争用问题。消息队列(Message Queue):
$ T* B9 }- g2 l! c) v7 o允许进程以消息的形式发送和接收数据。
V1 s: R+ o! o消息队列是一种先进先出(FIFO)的结构,支持不同类型的消息,使得进程可以基于消息类型进行处理。共享内存(Shared Memory):
' z2 q3 S7 r. W/ q Y- ~/ f进程之间共享同一块内存区域,允许它们直接读写数据。
. I) P6 w. Y5 g+ u f: z# n这是最有效的 IPC 方式,因为数据不需要在进程之间复制。- {6 y8 V; r! K/ t; z! d( W$ }
" M& U4 v6 P3 L1.3、POSIX IPC
4 N) D9 I3 S, d* c! ]. L7 f3 jPOSIX IPC 是 System V IPC 的改进版本,旨在解决 System V IPC 在灵活性和可移植性上的一些不足。2 a- ?- R# j1 R1 \2 U( N
; g3 u+ w1 q5 ?" L
POSIX 标准为 UNIX 系统间的兼容性提供了统一的接口,使得程序可以更方便地在不同的 UNIX 系统间移植。: {/ L4 d6 l& M6 _% Q. C
POSIX 信号量:
, o- n+ ^8 L$ V' G6 P$ |与 System V 信号量类似,用于进程同步,但提供了更灵活的接口和更强的实时性支持。POSIX 消息队列:
2 i- i" R% G. p/ g+ e改进了 System V 消息队列,允许指定消息的优先级,并提供更简单的接口。POSIX 共享内存:
j p' w# ?0 u1 m5 p* s与 System V 共享内存类似,但具有更好的兼容性和可移植性,接口设计更加现代化。$ ~6 F; z; H8 Y+ L! E- y0 ]: N
9 L. ]: U8 d4 L. N1.4、套接字(Socket)通信
, J7 [% H& z8 P; R3 i2 A [套接字是一种既可以用于本地进程间通信,也可以用于网络通信的机制,支持双向数据传输。
* L+ {" X* G2 z( V' g) W6 h
1 O1 \8 [$ z5 ]+ v. d0 J基于套接字的 IPC 可以实现非常灵活的通信模式,例如客户端-服务器架构,适合在多台计算机之间传递数据。+ o3 Y& w0 c! @5 m- G
3 k, r, B# P* B3 n0 o, g- F! e' D
各类 IPC 机制的对比和应用场景:
$ Z: t* n* d" A* r; t* J
3 v, t, K9 c. D0 s) m f6 {# F
bsbbcgpudkr64088526043.png
, [1 f, c" u& x. z' n& ?' i! K. M- ]) j$ f' u, A
23 w9 Z5 i: c' N
管道(Pipe), S |6 J9 @" X i8 h
管道是一种半双工(单向)的通信方式,通常用于父子进程之间的通信。一个进程可以向管道写入数据,另一个进程从管道读取数据。
! Y' c* y8 M" d7 ^" X8 c6 Q' M* h4 S9 E) T& I0 O
Linux 提供了无名管道和命名管道两种类型。
. p% J. f; A9 H, h( a u无名管道(Anonymous Pipe): U$ C- t- ?- q5 j# e [% d1 R
只能在具有亲缘关系的进程间使用,比如父进程和子进程。命名管道(Named Pipe 或 FIFO):
8 w7 d' @5 S. s6 M# i通过文件系统中的路径来创建,任意进程都可以访问。# F3 {. d2 E u$ g8 T
& Z2 d) b" V4 c' r/ y1 M7 \, r; W8 f
示例:! L( N8 A9 q/ C* R) ?* u" Y8 o; r
! d! W5 ]4 _. m9 q3 Lint main() { int fd[2]; pipe(fd); // 创建无名管道
% I8 ^, H7 c' |0 U9 S$ s+ s 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: %s4 v3 r0 O0 q7 u! d" h
", buffer); close(fd[0]); } return 0;}! r4 q! G6 t( E& t9 l# W
31 ?! G$ x$ n# z$ s
消息队列(Message Queue)
. B1 r6 U! @$ L2 @消息队列是一种先进先出的队列,允许进程以消息的形式发送和接收数据。3 D9 S M. T" Q8 k. q; I
$ J, `3 @* X7 g5 D
消息队列可以支持多种类型的消息,通过消息类型实现多种目的的通信。# F- d. i6 _; M) V; p) q2 I) X* g+ _
0 c/ L( D; j( ^5 R: k4 l3 _示例:进程A可以向队列发送一个带有特定类型的消息,而进程B可以根据消息类型进行处理。
6 S" _3 O2 i+ p, Q( E+ S$ ~
7 h+ A0 K$ o" C" ystruct msgbuf { long mtype; char mtext[100];};
F* O, f. ?( z: o4 p: s5 hint main() { key_t key = ftok("msgqueue", 65); int msgid = msgget(key, 0666 | IPC_CREAT); struct msgbuf message;
. r& ]/ J' q% O; k, E( B1 U message.mtype = 1; // 消息类型 snprintf(message.mtext, sizeof(message.mtext), "Hello Message Queue"); msgsnd(msgid, &message, sizeof(message.mtext), 0);6 ~( L* e& S0 }' T: b! o
return 0;}3 G, o& E0 ^# e# M' O) P* v
4& _, U3 V4 h4 M
共享内存(Shared Memory)" P0 {8 J# b: R9 g* w" C
共享内存是最快的 IPC 机制之一,因为进程之间直接访问同一块内存区域,而不需要拷贝数据。
3 c7 ^5 n* a0 S3 @) f. i h1 [1 [" p/ a m, |: T
通常使用 shmget()、shmat() 和 shmdt() 函数进行共享内存的创建和访问。: K I k( d. s' v, [ F
7 I3 y& b! K! Q0 U9 O
示例:4 v* a( f0 R* q' A- t; ?, L# |
( v! E* r2 i" Q: dint main() { key_t key = ftok("shmfile",65); int shmid = shmget(key, 1024, 0666|IPC_CREAT); char *str = (char*) shmat(shmid, (void*)0, 0);! f5 f3 |' H' F. E) U
strcpy(str, "Hello Shared Memory");: l' S! |. n( U# ]/ z' Z
printf("Data written in memory: %s
v1 J( u+ i7 j+ l, m/ L) W6 b", str); shmdt(str);0 T' p: R$ s- Z B% b
return 0;}: N2 f/ s$ O4 @/ G4 m
5
) } h4 E4 F$ f& u! n y信号量(Semaphore)
5 b% [7 g, D6 _/ P# Q' l. D信号量是一种用于进程同步的机制,通常用于控制多个进程对共享资源的访问。
" j$ g# X; C0 M7 p( g: Q. i0 j" W- M8 n
嵌入式系统中,信号量通常用来避免多个进程同时访问同一资源,防止数据竞争。
. n. J) I% `2 G, n i9 X" R" x- L* U# V' Y0 M" z4 `( o0 \4 E; r: ~
示例:信号量可以通过 semget() 和 semop() 函数来操作,用于锁定或解锁资源。, i9 K% T' W( f' ]+ G! {) M
$ I2 F" [# _) y) p. i' N0 W$ Mint 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操作9 U9 M( O) ?$ G' o: A% ^, L
semop(semid, &sem_lock, 1); // 上锁 printf("Critical section- h0 w6 z% F( \) F" K8 V
"); semop(semid, &sem_unlock, 1); // 解锁, f3 M* E4 z9 B
return 0;}' |# n+ D/ j! K
6
1 F/ r) ]8 \/ E' U2 u. ?套接字(Socket)/ J* `3 D0 Q5 d4 R) D4 J# i
套接字不仅支持本地进程间通信,还可以用于网络通信。# b5 h( S0 l, X
; f* b4 {) y9 s- G; i: s基于套接字的 IPC 支持双向通信,比较灵活,适合嵌入式系统中进程之间需要频繁且复杂的数据交互的情况。
) [. B$ m N- t* \ ]; W: z
+ i( V( ^: `) w2 N6 H示例:- v8 G( |4 z9 k8 S2 g0 C' i8 B) i( v
; _: b. ]& Q0 b4 Q5 Q3 m5 l! tint main() { int sv[2]; socketpair(AF_UNIX, SOCK_STREAM, 0, sv);7 y4 i8 m0 d+ }1 Z% a
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
2 p' e% i% T* n" l. V/ R8 ]1 o9 \", buffer); close(sv[0]); } return 0;}5 `/ q; P3 y3 ^. \# c% K
7' y U5 E& V5 k. Q7 M$ `, m6 c
信号(Signal)
7 l, @5 o% t' z$ D信号是用来通知进程发生某种事件的机制。进程可以捕获、忽略或处理信号,典型的信号包括 SIGINT(中断信号)和 SIGKILL(杀死进程信号)。9 n% y! b" A& ?* g; `7 X d
B* p1 P2 Q6 [7 H; O% G
示例:处理 SIGINT 信号(Ctrl+C)。
, I: [+ `* j4 t9 G
3 v- X; _/ Y$ _6 T6 {/ h1 svoid sigint_handler(int sig) { printf("Caught signal %d+ O% W5 c! L- @& T1 M( o$ u
", sig);}
( f8 l. C% T' |4 _; {- x ]int main() { signal(SIGINT, sigint_handler); while (1) { printf("Running...+ t) j6 K+ e% ~8 Z3 [) d' P
"); sleep(1); } return 0;}$ p |. u7 w8 [- l2 ~6 H
进程间通信的机制多种多样,选择合适的方式取决于应用场景的需求。
9 |; S4 S8 s; y
pxe3tci4tfg64088526143.jpg
: M) c4 `. T x+ O
qjqlous0j2064088526243.gif
# k A3 H$ H8 }' a$ k
点击阅读原文,更精彩~ |
|