嵌入式Linux应用程序开发详解-第8 章 进程间通信
linux下的进程间通信
详细的讲述进程间通信在这里绝对是不可能的事情,而且笔者很难有信心说自己对这一部分内容的认识达到了什么样的地步,所以在这一节的开头首先向大家推荐著名作者Richard Stevens的著名作品:《Advanced Programming in the UNIX Environment》,它的中文译本《UNIX环境高级编程》已有机械工业出版社出版,原文精彩,译文同样地道,如果你的确对在Linux下编程有浓厚的兴趣,那么赶紧将这本书摆到你的书桌上或计算机旁边来。
说这么多实在是难抑心中的景仰之情,言归正传,在这一节里,我们将介绍进程间通信最最初步和最最简单的一些知识和概念。
首先,进程间通信至少可以通过传送打开文件来实现,不同的进程通过一个或多个文件来传递信息,事实上,在很多应用系统里,都使用了这种方法。
但一般说来,进程间通信(IPC:InterProcess Communication)不包括这种似乎比较低级的通信方法。
Unix系统中实现进程间通信的方法很多,而且不幸的是,极少方法能在所有的Unix系统中进行移植(唯一一种是半双工的管道,这也是最原始的一种通信方式)。
而Linux作为一种新兴的操作系统,几乎支持所有的Unix下常用的进程间通信方法:管道、消息队列、共享内存、信号量、套接口等等。
下面我们将逐一介绍。
2.3.1 管道管道是进程间通信中最古老的方式,它包括无名管道和有名管道两种,前者用于父进程和子进程间的通信,后者用于运行于同一台机器上的任意两个进程间的通信。
无名管道由pipe()函数创建:#include <unistd.h>int pipe(int filedis[2]);参数filedis返回两个文件描述符:filedes[0]为读而打开,filedes[1]为写而打开。
filedes[1]的输出是filedes[0]的输入。
下面的例子示范了如何在父进程和子进程间实现通信。
#define INPUT 0#define OUTPUT 1void main() {int file_descriptors[2];/*定义子进程号*/pid_t pid;char buf[256];int returned_count;/*创建无名管道*/pipe(file_descriptors);/*创建子进程*/if((pid = fork()) == -1) {printf("Error in fork/n");exit(1);}/*执行子进程*/if(pid == 0) {printf("in the spawned (child) process.../n");/*子进程向父进程写数据,关闭管道的读端*/close(file_descriptors[INPUT]);write(file_descriptors[OUTPUT], "test data", strlen("test data"));exit(0);} else {/*执行父进程*/printf("in the spawning (parent) process.../n");/*父进程从管道读取子进程写的数据,关闭管道的写端*/close(file_descriptors[OUTPUT]);returned_count = read(file_descriptors[INPUT], buf, sizeof(buf));printf("%d bytes of data received from spawned process: %s/n",returned_count, buf);}}在Linux系统下,有名管道可由两种方式创建:命令行方式mknod系统调用和函数mkfifo。
linux系统进程间通信的方式
linux系统进程间通信的方式
Linux系统进程间通信的方式有多种,其中比较常见的有管道、消息队列、信号量、共享内存和套接字等。
1. 管道:管道是一种半双工的通信方式,其本质是一块内存缓冲区。
它分为匿名管道和命名管道,匿名管道只能用于父子进程之间的通信,而命名管道则可以用于任意两个进程之间的通信。
2. 消息队列:消息队列是一种通过内核实现的进程间通信机制,其可以实现多对多的进程通信。
消息队列可以设置消息的优先级和大小,发送方通过消息队列发送消息,接收方则通过读取消息队列的方式获取消息。
3. 信号量:信号量是一种用于同步多进程共享资源的机制。
它可以用来解决多个进程同时访问共享资源时所产生的竞争问题。
通过信号量机制,进程可以申请资源、释放资源以及等待资源。
4. 共享内存:共享内存是一种高效的进程间通信方式,它允许多个进程共享同一块物理内存空间。
多个进程可以直接访问这块内存,从而实现进程间数据的快速传递。
5. 套接字:套接字是一种跨网络的进程间通信方式,它可以实现不同主机上的进程之间的通信。
套接字可以用于实现客户端和服务器的通信,也可以用于实现进程之间的通信。
总的来说,不同的进程间通信方式有不同的应用场景,开发者需要根据实际的需求选择合适的进程间通信方式。
- 1 -。
Linux进程间通信信号(signal)
Linux进程间通信信号(signal)1. 概念: 1)信号是在软件层次上对中断机制的⼀种模拟,是⼀种异步通信⽅式 2)信号可以直接进⾏⽤户空间进程和内核进程之间的交互,内核进程也可以利⽤它来通知⽤户空间进程发⽣了哪些系统事件。
3)如果该进程当前并未处于执⾏态,则该信号就由内核保存起来,直到该进程恢复执⾏再传递给它;如果⼀个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。
2.⽤户进程对信号的响应⽅式: 1)忽略信号:对信号不做任何处理,但是有两个信号不能忽略:即SIGKILL及SIGSTOP。
2)捕捉信号:定义信号处理函数,当信号发⽣时,执⾏相应的处理函数。
3)执⾏缺省操作:Linux对每种信号都规定了默认操作3.信号: SIGINT:ctrl+c 终⽌信号 SIGQUIT:ctrl+\ 终⽌信号 SIGTSTP:ctrl+z 暂停信号 SIGALRM:闹钟信号收到此信号后定时结束,结束进程 SIGCHLD:⼦进程状态改变,⽗进程收到信号 SIGKILL:杀死信号4.相关函数:1)int kill(pid_t pid, int sig); 功能:信号发送 参数:pid:指定进程 sig:要发送的信号 返回值:成功 0;失败 -12)int raise(int sig); 功能:进程向⾃⼰发送信号 参数:sig:信号 返回值:成功 0;失败 -13)unsigned int alarm(unsigned int seconds) 功能:在进程中设置⼀个定时器 参数:seconds:定时时间,单位为秒 返回值:如果调⽤此alarm()前,进程中已经设置了闹钟时间,则返回上⼀个闹钟时间的剩余时间,否则返回0。
注意:⼀个进程只能有⼀个闹钟时间。
如果在调⽤alarm时已设置过闹钟时间,则之前的闹钟时间被新值所代替4)int pause(void); 功能:⽤于将调⽤进程挂起直到收到信号为⽌。
Linux进程间通信
如何指定信号处理方式?
表 7-16 所需头文件 函数原型 #include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact) signum:信号代码,可以为除 SIGKILL 及 SIGSTOP 外的任何一个特定有效的信号 Act:指向 struct sigaction struct sigaction { void (*sa_handler)(int signo); sigset_t sa_mask; int sa_flags; void (*sa_restore)(void); } Oldact:指向 struct sigaction 函数返回值 0 表示成功, -1 表示有错误发生 siga ct ion ( ) 函数语法要点
void main() { printf("Waiting for signal SIGINT or SIGQUIT...\n"); signal(SIGINT, my_func); //收到信号SIGINT,转去执行函数my_func for(;;); exit(0); }
例2:子进程等收到信号才结束
if (pid == 0) {/*子进程*/ printf("Child(pid : %d) is waiting for any signal\n", getpid()); raise(SIGSTOP);// 使子进程暂停 exit(0); }
else {/*父进程*/ if ((waitpid(pid, NULL, WNOHANG)) == 0) { if ((ret = kill(pid, SIGKILL)) == 0) //向子进程发结束信号 printf("Parent kill %d\n",pid); } waitpid(pid, NULL, 0); exit(0); }
进程和进程间通信
进程和进程间通信进程是操作系统中的一个基本概念,它代表了一个正在运行的程序实例。
在现代操作系统中,多个进程可以同时运行,并且需要进行相互之间的通信和协调。
进程间通信(Inter-Process Communication,IPC)是指不同进程之间进行数据交换和共享的机制。
一、进程间通信的需求与作用进程间通信的需求主要体现在以下几个方面:1. 数据共享:不同进程可能需要共享数据,以便实现信息的交换和共同处理。
2. 信息传递:进程之间可能需要进行消息的传递,以便进行协调和同步。
3. 资源共享:进程可能需要共享系统资源,如文件、设备等。
进程间通信的作用主要包括:1. 提高系统性能:进程间通信可以使不同进程并发执行,提高系统整体的运行效率。
2. 实现协作:不同进程之间可以交换信息、协调工作,实现更复杂的任务。
3. 实现分布式计算:通过进程间通信,可以将任务分布到不同的进程或计算机上进行并行处理。
二、进程间通信的方式在实际应用中,进程间通信可以通过多种方式来实现:1. 管道(Pipe):管道是一种半双工的通信方式,可以用于具有亲缘关系的进程之间进行通信。
常见的管道实现有匿名管道和有名管道。
2. 消息队列(Message Queue):消息队列是一种通过系统内核提供的消息缓冲区进行通信的方式,具有高度灵活性和可靠性。
3. 信号量(Semaphore):信号量是一种计数器,用于实现进程之间的同步和互斥操作,常用于控制对共享资源的访问。
4. 共享内存(Shared Memory):共享内存是一种将同一块物理内存映射到多个进程的通信方式,可以实现数据的快速共享。
5. 套接字(Socket):套接字是一种通信机制,可以用于实现不同计算机之间的进程间通信,常用于网络编程。
以上只是进程间通信的一些常见方式,实际上还有其他方式如信号、文件、RPC(远程过程调用)等。
在选择具体的通信方式时,需要根据实际场景需求进行综合考虑。
Linux_进程之间的通信
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2184 root 20 0 64220 4812 3908 R 6.7 0.2 0:00.01 top
1 root 20 0 178784 13560 8556 S 0.0 0.7 0:04.24 systemd 2 root 20 0 0 0 0 S 0.0 0.0 0:00.02 kthreadd 3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp 4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_par_gp 5 root 20 0 0 0 0 I 0.0 0.0 0:00.69 kworker/0:0-xfs-cil/dm-0 6 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H-kblockd ...............
//此处的load average就表示负载平均值,这三个值代表最近1、5和15分钟的负载情况。
[root@localhost ~]# top top - 09:26:24 up 23 min, 4 users, load average: 0.00, 0.00, 0.00 Tasks: 219 total, 1 running, 218 sleeping, 0 stopped, 0 zombie %Cpu(s): 0.0 us, 0.0 sy, 0.0 ni, 99.7 id, 0.0 wa, 0.2 hi, 0.2 si, 0.0 st MiB Mem : 1965.1 total, 1405.6 free, 260.4 used, 299.1 buff/cache MiB Swap: 2096.0 total, 2096.0 free, 0.0 used. 1545.0 avail Mem
linux的进程间的通信机制
linux的进程间的通信机制
Linux进程间通信的方式有多种,以下是一些常用的通信机制:
1. 管道(pipe):管道是一种半双工的通信方式,它可以在具
有父子关系的进程间进行通信。
管道有两种类型:普通管道(匿名管道)和命名管道(FIFO)。
2. 消息队列(message queue):消息队列是一种通过消息传
递进行进程间通信的机制。
进程可以通过将消息发送到消息队列中,另一个进程可以从该队列中读取消息。
3. 共享内存(shared memory):共享内存是一种高效的进程
间通信方式,允许多个进程访问同一段内存。
这种通信方式适用于需要大量数据交换的进程。
4. 信号(signal):信号是一种软件中断机制,用于通知进程
发生了一些特定事件。
发送信号的进程可以将信号发送给另一个进程,接收进程可以定义信号的处理函数。
5. 信号量(semaphore):信号量是一种用于进程同步和互斥
的机制。
它允许多个进程共享一个计数器,用于控制对临界资源的访问。
6. 套接字(socket):套接字是一种用于网络通信的机制,它
允许不同机器间的进程进行通信。
套接字提供了一种编程接口,使得进程可以通过互联网进行数据传输。
这些通信机制各有优缺点,应根据具体的需求选择合适的方式。
Linux的进程和进程间通信 操作系统课件
例子1(续)
} else if(child==0) { int i; printf("I am the child:%ld\n",getpid()); for(i=0;i<1000000;i++) i++; i=5; printf("I exit with %d\n",i); exit(i); } while(((child=wait(&status))==-1)&(errno==EINTR)); }
区分父进程和子进程:
◦ 跟踪fork返回值
失败:-1 否则
父进程fork 返回子进程的ID fork 子进程返回0
可根据这个返回值来区分父子进程
调用系统程序
调用系统程序, 可以使用系统调用exec 族调用。 exec 族调用有着5 个函数:
#include <unistd.h> int execl(const char *path,const char *arg,...); int execlp(const char *file,const char *arg,...); int execle(const char *path,const char *arg,...); int execv(const char *path,char *const argv[]); int execvp(const char *file,char *const argv[]):
如何在Linux终端中进行进程间通信
如何在Linux终端中进行进程间通信进程间通信(Inter-process Communication,简称IPC)是操作系统中重要的概念,用于实现不同进程之间的数据交换和协作。
在Linux终端中,有多种方法可以进行进程间通信,包括管道(Pipe)、信号(Signal)、共享内存(Shared Memory)和套接字(Socket)等。
本文将介绍这些方法的基本原理以及在Linux终端中的应用。
一、管道(Pipe)管道是最简单的一种进程间通信方式,它将一个进程的输出直接传递给另一个进程的输入。
在Linux终端中,管道可以通过使用竖线符号(|)来进行连接,例如:```$ command1 | command2```其中,command1为第一个进程,command2为第二个进程。
通过管道,command1的输出将作为command2的输入。
二、信号(Signal)信号是一种进程间异步通信的机制,它用于通知目标进程发生了某个特定的事件。
在Linux终端中,可以使用kill命令向指定进程发送信号,例如:```$ kill -SIGUSR1 <pid>```其中,SIGUSR1是一个自定义的信号,<pid>是目标进程的进程号。
三、共享内存(Shared Memory)共享内存是一种高效的进程间通信方式,它将一块内存区域映射到多个进程的地址空间中,使它们可以直接访问该内存区域。
在Linux终端中,可以使用shmget、shmat等系统调用来创建和操作共享内存。
四、套接字(Socket)套接字是一种支持网络通信的IPC机制,通过套接字,不仅可以在同一台主机上的不同进程间进行通信,还可以在不同主机间进行通信。
在Linux终端中,可以使用socket、bind、listen、accept等系统调用来创建和操作套接字。
总结以上介绍了Linux终端中常用的几种进程间通信方式,包括管道、信号、共享内存和套接字。
linux进程间通信(中嵌教育-嵌入式linux开发课件)
2.2 管道读写
管道主要用于不同进程间通信。实际上,通常先创建 一个管道,再通过fork函数创建一个子进程。
图2 父子进程管道的文件描述符对应关系
子进程写入和父进程读的命名管道:
图 3 关闭父进程fd[1] 和 子进程[0]
2.3 管道读写注意事项
2.4 标准流管道
与linux中文件操作有文件流的标准I/O一样,管道的 操作也支持基于文件流的模式。接口函数如下 库函数:popen(); 原型: FILE *popen ( char *command, char *type); 返回值:如果成功,返回一个新的文件流。如果 无法创建进程或者管道,返回NULL。 管道中数据流的方向是由第二个参数type控制的。此 参数可以是r或者w,分别代表读或写。但不能同时为读 和写。在Linux系统下,管道将会以参数type中第一个字 符代表的方式打开。所以,如果你在参数type中写入rw, 管道将会以读的方式打开。
Linux 中的信号:
1) SIGHUP 2) SIGINT 3) SIGQUIT 5) SIGTRAP 6) SIGIOT 7) SIGBUS 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 13) SIGPIPE 14) SIGALRM 15) SIGTERM 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 22) SIGTTOU 23) SIGURG 24) SIGXCPU 26) SIGVTALRM 27) SIGPROF 29) SIGIO 30) SIGPWR 4) SIGILL 8) SIGFPE 12) SIGUSR2 17) SIGCHLD 21) SIGTTIN 25) SIGXFSZ 28) SIGWINCH
Linux下进程间通信的原理
Linux下进程间通信的原理了解 Linux IPC 相关的概念和原理有助于我们理解 Binder 通信原理。
因此,在介绍 Binder 跨进程通信原理之前,我们先聊聊 Linux 系统下传统的进程间通信是如何实现。
⼀、基本概念Linux 进程间通信的原理图如下图所⽰:可以看出来,Liunx 中跨进程通信涉及到的⼀些基本概念如下:进程隔离进程空间划分:⽤户空间(User Space)/内核空间(Kernel Space)系统调⽤:⽤户态/内核态1. 进程隔离简单的说就是操作系统中,进程与进程间内存是不共享的。
两个进程就像两个平⾏的世界,A 进程没法直接访问 B 进程的数据,这就是进程隔离的通俗解释。
A 进程和B 进程之间要进⾏数据交互就得采⽤特殊的通信机制:进程间通信(IPC)。
2. 进程空间划分操作系统的核⼼是内核,独⽴于普通的应⽤程序,可以访问受保护的内存空间,也可以访问底层硬件设备的权限。
为了保护⽤户进程不能直接操作内核,保证内核的安全,操作系统从逻辑上将虚拟空间划分为⽤户空间(User Space)和内核空间(Kernel Space)。
简单的说就是,内核空间(Kernel)是系统内核运⾏的空间,⽤户空间(User Space)是⽤户程序运⾏的空间。
为了保证安全性,它们之间是隔离的。
3. 系统调⽤:⽤户态与内核态虽然从逻辑上进⾏了⽤户空间和内核空间的划分,但不可避免的⽤户空间需要访问内核资源,⽐如⽂件操作、访问⽹络等等。
为了突破隔离限制,就需要借助系统调⽤来实现。
系统调⽤是⽤户空间访问内核空间的唯⼀⽅式,保证了所有的资源访问都是在内核的控制下进⾏的,避免了⽤户程序对系统资源的越权访问,提升了系统安全性和稳定性。
Linux 使⽤两级保护机制:0 级供系统内核使⽤,3 级供⽤户程序使⽤。
当⼀个任务(进程)执⾏系统调⽤⽽在内核代码中执⾏时,称进程处于内核运⾏态(内核态)。
此时处理器处于特权级最⾼的(0级)内核代码中执⾏。
嵌入式开发中的进程间通信
嵌入式开发中的進程間通信在嵌入式开发中,进程间通信(Inter-Process Communication,IPC)是一个非常重要的概念和技术。
嵌入式系统中的多个进程或任务可能需要相互通信和协作,以完成复杂的功能和任务。
本文将介绍嵌入式开发中的进程间通信技术,包括原理、常用方法和应用。
一、进程间通信的概念和原理在嵌入式系统中,进程是指执行中的程序实例,可以独立运行并具有自己的地址空间和上下文。
不同的进程可能需要相互通信和共享资源,以实现系统的功能和目标。
进程间通信即是指不同进程之间进行数据传递和信息交流的过程。
进程间通信的原理基于操作系统的支持,通过提供一组机制和接口,使得不同进程可以安全地进行数据传输和共享。
进程间通信可以在同一个处理器上的不同任务之间进行,也可以在不同处理器上的任务之间进行。
二、进程间通信的常用方法在嵌入式系统中,有多种方法可以实现进程间通信。
下面将介绍几种常用的方法。
1. 共享内存共享内存是一种高效的进程间通信方法,它允许不同的进程共享同一块物理内存区域。
不同的进程可以通过读写共享内存来实现数据的传递和共享。
共享内存的关键在于同步和互斥机制,确保各个进程对共享内存的访问不会发生冲突和竞争。
2. 信号量信号量是一种用于进程间同步和互斥的机制。
它可以用来解决多个进程访问共享资源时可能发生的冲突和竞争问题。
通过设置信号量的初值和对信号量进行P(阻塞)和V(唤醒)操作,不同进程可以按照特定的顺序进行访问和操作共享资源。
3. 消息队列消息队列是一种基于消息传递的进程间通信方法。
不同进程可以通过向消息队列发送消息和从消息队列接收消息来进行通信。
消息队列一般按照先进先出(FIFO)的原则进行消息的排队和传递。
4. 管道和套接字管道和套接字是一种基于文件描述符的进程间通信方法。
它们允许不同进程之间通过读写文件描述符进行数据传输和通信。
管道一般用于同一台主机上的进程通信,而套接字则可以在不同主机上的进程之间进行通信。
linux进程间通信机制
linux进程间通信机制Linux是一种广泛使用的操作系统,它提供了丰富的进程间通信机制,可以使不同的进程之间进行有效的数据交换和协作。
进程间通信(Inter-Process Communication,IPC)是指在多个进程之间传递数据和信息的机制。
本文将介绍Linux中常用的几种进程间通信机制,包括管道、信号量、消息队列和共享内存。
一、管道管道是一种最基本的进程间通信机制,在Linux中以“|”符号表示。
它可以将一个进程的输出直接作为另一个进程的输入,实现它们之间的数据传递。
管道可以分为匿名管道和命名管道两种。
匿名管道只能用于具有亲缘关系的进程之间,而命名管道则可以用于不具有亲缘关系的进程之间。
二、信号量信号量是一种用于进程间同步和互斥的机制。
在Linux中,信号量可以通过System V信号量和POSIX信号量两种方式实现。
System V信号量使用的是整型变量,可以通过P、V操作来实现进程的阻塞和唤醒。
而POSIX信号量则使用的是结构体,可以通过sem_wait、sem_post等函数来实现进程的同步和互斥。
三、消息队列消息队列是一种进程间传递消息的机制,可以在不同的进程之间传递不同类型的数据。
在Linux中,消息队列由消息队列标识符和消息类型组成。
发送进程可以通过msgsnd函数向消息队列发送消息,接收进程可以通过msgrcv函数从消息队列接收消息。
消息队列可以实现进程之间的异步通信,提高系统的吞吐量和响应速度。
四、共享内存共享内存是一种将内存段映射到多个进程地址空间的机制,可以实现多个进程之间的数据共享。
在Linux中,可以通过shmget函数创建共享内存,通过shmat函数将共享内存附加到进程的地址空间,通过shmdt函数将共享内存从进程的地址空间分离。
共享内存可以提高进程之间的数据传输效率,但也需要注意进程间的同步和互斥问题。
总结:Linux提供了多种进程间通信机制,包括管道、信号量、消息队列和共享内存。
浅析嵌入式Linux中进程间的几种通信方式
浅析嵌入式Linux中进程间的几种通信方式
线程间通信:由于多线程共享地址空间和数据空间,所以多个线程间的通信是一个线程的数据可以直接提供给其他线程使用,而不必通过操作系统。
所以线程间通信和同步的方式主要有锁、信号、信号量进程间的通信则不同,它的数据空间的独立性决定了它的通信相对比较复杂,需要通过操作系统。
通信机制主要有:管道、有名管道、消息队列、信号量、共享空间、信号、套接字(socket)。
下面简单介绍下进程间的几种通信方式:
管道:它传递数据是单向性的,只能从一方流向另一方,也就是一种半双工的通信方式;只用于有亲缘关系的进程间的通信,亲缘关系也就是父子进。
linux进程间通信
进程间通信在Linux系统中,以进程为单位分配和管理资源。
由于保护的缘故,一个进程不能直接访问另一个进程的资源,也就是说,进程之间互相封闭。
但在一个复杂的应用系统中,通常会使用多个相关的进程来共同完成一项任务,因此要求进程之间必须能够互相通信,从而来共享资源和信息。
所以,一个操作系统内核必须提供进程间的通信机制(IPC)。
进程间通信有如下一些目的:数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。
共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
资源共享:多个进程之间共享同样的资源。
为了作到这一点,需要内核提供锁和同步机制。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
进程通过与内核及其它进程之间的互相通信来协调它们的行为。
Linux支持多种进程间通信(IPC)机制,信号和管道是其中的两种。
除此之外,Linux还支持System V 的IPC 机制(用首次出现的Unix版本命名)。
5.1 信号(Signals)信号(Signals )是Unix系统中使用的最古老的进程间通信的方法之一。
操作系统通过信号来通知进程系统中发生了某种预先规定好的事件(一组事件中的一个),它也是用户进程之间通信和同步的一种原始机制。
一个键盘中断或者一个错误条件(比如进程试图访问它的虚拟内存中不存在的位置等)都有可能产生一个信号。
Shell也使用信号向它的子进程发送作业控制信号。
信号是在Unix System V中首先引入的,它实现了15种信号,但很不可靠。
BSD4.2解决了其中的许多问题,而在BSD4.3中进一步加强和改善了信号机制。
但两者的接口不完全兼容。
第8章、进程间通信
嵌入式学院—华清远见旗下品牌:《嵌入式Linux应用程序开发标准教程》——第8章、进程间通信掌握Linux中管道的读写掌握Linux中有名管道的创建读写方法掌握Linux中消息队列的处理掌握Linux共享内存的处理《嵌入式Linux应用程序开发标准教程》——第8章、进程间通信8.1 Linux下进程间通信概述在上一章中,读者已经知道了进程是一个程序的一次执行。
这里所说的进程一般是指运行在用户态的进程,而由于处于用户态的不同进程之间是彼此隔离的,就像处于不同城市的人们,它们必须通过某种方式来进行通信,例如人们现在广泛使用的手机等方式。
本章就是讲述如何建立这些不同的通话方式,就像人们有多种通信方式一样。
Linux下的进程通信手段基本上是从UNIX平台上的进程通信手段继承而来的。
而对UNIX发展做出重大贡献的两大主力A T&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间的通信方面的侧重点有所不同。
前者是对UNIX早期的进程间通信手段进行了系统的改进和扩充,形成了“system V IPC”,其通信进程主要局限在单个计算机内;后者则跳过了该限制,形成了基于套接口(socket)的进程间通信机制。
而Linux则把两者的优势都继承了下来,如图8.1所示。
⏹UNIX⏹System V信号量以及System V⏹Posix 信号量以及Posix现在在Linux中使用较多的进程间通信方式主要有以下几种。
(1)管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
(2)信号(Signal):信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一样的。
(3)消息队列(Messge Queue):消息队列是消息的链接表,包括Posix消息队列SystemV消息队列。
进程间通信详解
进程间通信详解⼀、管道管道,通常指⽆名管道,是 UNIX 系统IPC最古⽼的形式。
1、特点:1. 它是半双⼯的(即数据只能在⼀个⽅向上流动),具有固定的读端和写端。
2. 它只能⽤于具有亲缘关系的进程之间的通信(也是⽗⼦进程或者兄弟进程之间)。
3. 它可以看成是⼀种特殊的⽂件,对于它的读写也可以使⽤普通的read、write 等函数。
只存在于内存中。
⼆、FIFOFIFO,也称为命名管道,它是⼀种⽂件类型。
1、特点1. FIFO可以在⽆关的进程之间交换数据,与⽆名管道不同。
2. FIFO有路径名与之相关联,它以⼀种特殊设备⽂件形式存在于⽂件系统中。
三、消息队列消息队列,是消息的链接表,存放在内核中。
⼀个消息队列由⼀个标识符(即队列ID)来标识。
1、特点1. 消息队列是⾯向记录的,其中的消息具有特定的格式以及特定的优先级。
2. 消息队列独⽴于发送与接收进程。
进程终⽌时,消息队列及其内容并不会被删除。
3. 消息队列可以实现消息的随机查询,消息不⼀定要以先进先出的次序读取,也可以按消息的类型读取。
四、信号量信号量(semaphore)与已经介绍过的 IPC 结构不同,它是⼀个计数器。
信号量⽤于实现进程间的互斥与同步,⽽不是⽤于存储进程间通信数据。
1、特点1. 信号量⽤于进程间同步,若要在进程间传递数据需要结合共享内存。
2. 信号量基于操作系统的 PV 操作,程序对信号量的操作都是原⼦操作。
3. 每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,⽽且可以加减任意正整数。
4. ⽀持信号量组五、共享内存共享内存(Shared Memory),指两个或多个进程共享⼀个给定的存储区。
1、特点1. 共享内存是最快的⼀种 IPC,因为进程是直接对内存进⾏存取。
2. 因为多个进程可以同时操作,所以需要进⾏同步。
3. 信号量+共享内存通常结合在⼀起使⽤,信号量⽤来同步对共享内存的访问。
六、socket这是⼀种更为⼀般得进程间通信机制,它可⽤于⽹络中不同机器之间的进程间通信,应⽤⾮常⼴泛。
Linux环境编程进程间通信机制理解
Linux环境编程进程间通信机制理解⼀、Linux系统调⽤主要函数⾸先,认识⼀下Linux下系统调⽤的主要函数,为后⾯进程与通信等做好铺垫。
以下是 Linux 系统调⽤的⼀个列表,包含了⼤部分常⽤系统调⽤和由系统调⽤派⽣出的函数。
fork创建⼀个新进程clone按指定条件创建⼦进程execve运⾏可执⾏⽂件exit中⽌进程_exit⽴即中⽌当前进程sleep(n)睡眠(等待/阻塞),n 为秒的单位getpid 获取进程标识号getppid获取⽗进程标识号pause挂起进程,等待信号wait(参数)等待⼦进程终⽌waitpid等待指定⼦进程终⽌kill向进程或进程组发信号pipe创建管道⼆、创建进程接下来这部分相当于程序设计,通过系统调⽤创建进程,然后根据执⾏顺序进⾏判断,理解主进程和⼦进程的关系。
1、创建⼦进程系统调⽤fork()#include <unistd.h>#include <sys/types.h>#include<stdio.h>int main (){pid_t pid; /* pid_t 是 short 类型 */pid=fork();if (pid < 0)printf("error in fork!");else if (pid == 0)printf("i am the child process, my process id is %d\n",getpid());elseprintf("i am the parent process, my process id is %d\n",getpid());return0;}这个程序很好理解:fork()返回值0,进⼊⼦进程,返回值1,进⼊⽗进程,-1则是创建失败。
主要理解⽗⼦进程执⾏顺序是否与程序结构(判断语句前后)有关,所以再次进⾏以下测试,修改了判断语句顺序:#include <unistd.h>#include <sys/types.h>#include<stdio.h>int main (){pid_t pid; /* pid_t 是 short 类型 */pid=fork();if (pid < 0)printf("error in fork!");else if (pid > 0)printf("i am the parent process, my process id is %d\n",getpid());elseprintf("i am the child process, my process id is %d\n",getpid());return0;}根据实验结果如图,对⽐之后发现运⾏结果相同,说明⽗⼦进程运⾏顺序与判断语句次序⽆关,始终是⽗进程优先执⾏。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
“黑色经典”系列之《嵌入式Linux应用程序开发详解》第8章进程间通信本章目标在上一章中,读者已经学会了如何创建进程以及如何对进程进行基本的控制,而这些都只是停留在父子进程之间的控制,本章将要学习不同的进程间进行通信的方法,通过本章的学习,读者将会掌握如下内容。
掌握Linux中管道的基本概念掌握Linux中管道的创建掌握Linux中有名管道的创建读写方法掌握Linux共享内存的处理华清远见<嵌入式Linux应用开发班>培训教材 8.1 Linux下进程间通信概述在上一章中,读者已经知道了进程是一个程序的一次执行的过程。
这里所说的进程一般是指运行在用户态的进程,而由于处于用户态的不同进程之间是彼此隔离的,就像处于不同城市的人们,它们必须通过某种方式来提供通信,例如人们现在广泛使用的手机等方式。
本章就是讲述如何建立这些不同的通话方式,就像人们有多种通信方式一样。
Linux下的进程通信手段基本上是从UNIX平台上的进程通信手段继承而来的。
而对UNIX发展做出重大贡献的两大主力A T&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间的通信方面的侧重点有所不同。
前者是对UNIX早期的进程间通信手段进行了系统的改进和扩充,形成了“system V IPC”,其通信进程主要局限在单个计算机内;后者则跳过了该限制,形成了基于套接口(socket)的进程间通信机制。
而Linux则把两者的优势都继承了下来,如图8.1所示。
•UNIX进程间通信(IPC)方式包括管道、FIFO、信号。
图8.1 进程间通信发展历程•System V进程间通信(IPC)包括System V消息队列、System V信号灯、System V共享内存区。
•Posix 进程间通信(IPC)包括Posix消息队列、Posix信号灯、Posix共享内存区。
现在在Linux中使用较多的进程间通信方式主要有以下几种。
(1)管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
(2)信号(Signal):信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知接受进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一样的。
华清远见<嵌入式Linux应用开发班>培训教材>培训教材(3)消息队列:消息队列是消息的链接表,包括Posix 消息队列systemV 消息队列。
它克服了前两种通信方式中信息量有限的缺点,具有写权限的进程可以向消息队列中按照一定的规则添加新消息;对消息队列有读权限的进程则可以从消息队列中读取消息。
(4)共享内存:可以说这是最有用的进程间通信方式。
它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。
这种通信方式需要依靠某种同步机制,如互斥锁和信号量等。
(5)信号量:主要作为进程间以及同一进程不同线程之间的同步手段。
(6)套接字(Socket ):这是一种更为一般的进程间通信机制,它可用于不同机器之间的进程间通信,应用非常广泛。
本章会详细介绍前4种进程通信方式,对第5种通信方式将会在第10章中单独介绍。
8.2 管道通信出了管输。
图8.2 管道的通信过程管道是Linux 中进程间通信的一种方式。
这里所说的管道主要指无名管道,它具有如下特点。
• 它只能用于具有亲缘关系的进程之间的通信(也就是父子进程或者兄弟进程之间)。
• 它是一个半双工的通信模式,具有固定的读端和写端。
• 管道也可以看成是一种特殊的文件,对于它的读写也可以使用普通的read 、write 等QQ:313638714函数。
但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
8.2.2 管道创建与关闭1.管道创建与关闭说明管道是基于文件描述符的通信方式,当一个管道建立时,它会创建两个文件描述符fds[0]和fds[1],其中fds[0]固定用于读管道,而fd[1]固定用于写管道,如图8.3所示,这样就构成了一个半双工的通道。
个文件注意一个管道共享了多对文件描述符时,若将其中的一对读写文件描述符都删除,则该管道就失效。
2.管道创建函数创建管道可以通过调用pipe来实现,下表8.1列出了pipe函数的语法要点。
表8.1 pipe函数语法要点所需头文件#include <unistd.h>函数原型int pipe(int fd[2])函数传入值fd[2]:管道的两个文件描述符,之后就可以直接操作这两个文件描述符成功:0函数返回值出错:−1华清远见<嵌入式Linux应用开发班>培训教材QQ:313638714 3.管道创建实例创建管道非常简单,只需调用函数pipe即可,如下所示:程序运行后先成功创建一个无名管道,之后再将其关闭。
8.2.3 管道读写1.管道读写说明用pipe函数创建的管道两端处于一个进程中,由于管道是主要用于在不同进程间通信的,因此这在实际应用中没有太大意义。
实际上,通常先是创建一个管道,再通过fork()函数创建一子进程,该子进程会继承父进程所创建的管道,这时,父子进程管道的文件描述符对应关系就如图8.4所示。
>培训教材图8.4 父子进程管道的文件描述符对应关系图8.5 关闭父进程fd[1]和子进程fd[0]同样,也可以关闭父进程的fd[0]和子进程的fd[1],这样就可以建立一条“父进程写,子进程读”的通道。
另外,父进程还可以创建多个子进程,各个子进程都继承了相应的fd[0]和fd[1],这时,只需要关闭相应端口就可以建立其各子进程之间的通道。
想一想为什么无名管道只能建立具有亲缘关系的进程之间?华清远见<嵌入式Linux应用开发班>培训教材QQ:313638714 2.管道读写实例在本例中,首先创建管道,之后父进程使用fork函数创建子进程,之后通过关闭父进程的读描述符和子进程的写描述符,建立起它们之间的管道通信。
>培训教材•只有在管道的读端存在时向管道中写入数据才有意义。
否则,向管道中写入数据的进程将收到内核传来的SIFPIPE信号(通常Broken pipe错误)。
•向管道中写入数据时,linux将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。
如果读进程不读取管道缓冲区中的数据,那么写操作将会一直阻塞。
•父子进程在运行时,它们的先后次序并不能保证,因此,在这里为了保证父进程已经关闭了读描述符,可在子进程中调用sleep函数。
8.2.4 标准流管道1.标准流管道函数说明与Linux中文件操作有基于文件流的标准I/O操作一样,管道的操作也支持基于文件流的模式。
这种基于文件流的管道主要是用来创建一个连接到另一个进程的管道,这里的“另一个进程”也就是一个可以进行一定操作的可执行文件,例如,用户执行“cat popen.c”或者自己编写的程序“hello”等。
由于这一类操作很常用,因此标准流管道就将一系列的创建华清远见<嵌入式Linux应用开发班>培训教材>培训教材过程合并到一个函数popen 中完成。
它所完成的工作有以下几步。
• 创建一个管道。
• fork 一个子进程。
• 在父子进程中关闭不需要的文件描述符。
• 执行exec 函数族调用。
• 执行函数中所指定的命令。
这个函数的使用可以大大减少代码的编写量,但同时也有一些不利之处,例如,它没有前面管道创建的函数灵活多样,并且用popen 创建的管道必须使用标准I/O 函数进行操作,但不能使用前面的read 、write 一类不带缓冲的I/O 函数。
与之相对应,关闭用popen 创建的流管道必须使用函数pclose 来关闭该管道流。
该函数关闭标准I/O 流,并等待命令执行结束。
2.函数格式popen 和pclose 函数格式如表8.2和表8.3所示。
表8.3 pclose 函数语法要点所需头文件 #include <stdio.h> 函数原型 int pclose(FILE *stream) 函数传入值 stream :要关闭的文件流成功:返回popen 中执行命令的终止状态 函数返回值出错:−13.函数使用实例在该实例中,使用popen 来执行“ps -ef ”命令。
可以看出,popen 函数的使用能够使程序变得短小精悍。
/*popen.c*/QQ:313638714华清远见<嵌入式Linux应用开发班>培训教材QQ:313638714 《嵌入式 Linux 应用程序开发详解》——第 8 章、进程间通信 75 76root root1836 2020S Rsh -c ps -ef ps –ef8.2.5FIFO1.有名管道说明 前面介绍的管道是无名管道,它只能用于具有亲缘关系的进程之间,这就大大地限制了 管道的使用。
有名管道的出现突破了这种限制, 它可以使互不相关的两个进程实现彼此通信。
该管道可以通过路径名来指出,并且在文件系统中是可见的。
在建立了管道之后,两个进程 就可以把它当作普通文件一样进行读写操作,使用非常方便。
不过值得注意的是,FIFO 是严 格地遵循先进先出规则的,对管道及 FIFO 的读总是从开始处返回数据,对它们的写则把数 据添加到末尾,它们不支持如 lseek()等文件定位操作。
有名管道的创建可以使用函数 mkfifo(),该函数类似文件中的 open()操作,可以指定管 道的路径和打开的模式。
小知识用户还可以在命令行使用“mknod 管道名 p”来创建有名管道。
在创建管道成功之后,就可以使用 open、read、write 这些函数了。
与普通文件的开发设 置一样,对于为读而打开的管道可在 open 中设置 O_RDONLY,对于为写而打开的管道可在 open 中设置 O_WRONLY,在这里与普通文件不同的是阻塞问题。
由于普通文件的读写时不 会出现阻塞问题, 而在管道的读写中却有阻塞的可能, 这里的非阻塞标志可以在 open 函数中 设定为 O_NONBLOCK。
下面分别对阻塞打开和非阻塞打开的读写进行一定的讨论。
对于读进程 • 若该管道是阻塞打开,且当前 FIFO 内没有数据,则对读进程而言将一直阻塞直到有 数据写入。
• 若该管道是非阻塞打开,则不论 FIFO 内是否有数据,读进程都会立即执行读操作。
对于写进程 • 若该管道是阻塞打开,则写进程而言将一直阻塞直到有读进程读出数据。
• 若该管道是非阻塞打开,则当前 FIFO 内没有读操作,写进程都会立即执行读操作。