无名管道和有名管道区别
- 格式:docx
- 大小:17.45 KB
- 文档页数:5
复习题一、填空题1、Linux操作系统是Unix 操作系统的一个克隆版本。
2、Linux的命令运行环境昌Shell,它是一种命令解释器,在用户和操作系统之间提供了一个交互接口。
3、Linux系统中有三个基本的文件类型:普通文件、目录文件和设备文件。
4、Linux系统通过目录将系统中所有的文件分级、分层组织在一起,形成了Linux文件系统的树型层次结构。
5、在Linux系统中建立新目录的命令是mkdir 。
6、Linux编程可分为Shell 编程和高级语言编程。
7、Linux系统提供了许多文本编辑程序,比较常用的有vi 和emacs 等。
8、要使用make,必须编写一个叫Makefile 的文件。
9、autoconf 是一个用于生成可以自动配置软件源代码包以适应多种类Unix系统的shell 脚本的工具。
10、Automake 是一个从文件Makefile.am中自动生成Makefile.in文件的工具。
11、Linux的文件是个简单的字节序列。
12、对于Linux而言,所有对设备和文件的操作都使用文件描述符。
13、调用open 函数可以打开或创建一个文件。
14、设置文件的存取权限,分为属主、组用户和其他用户三类。
每类分为读、写和执行权限。
15、第一个进程都有一个目录与之相连,它称为当前工作目录,或简单地称为工作目录。
16、当打开一个流时,标准输入输出函数返回一个FILE结构的指针。
17、在三个流是在执行程序时自动打开的。
它们是标准输入、标准输出和标准错误输出。
18、有3种类型的无格式I/O 函数可用来读写流,它们是字符I/O函数、行I/O函数和块I/O函数。
19、每一个流对象内部都保持着两个指示器:一个是错误指示器,当读写文件出错时该指示器被设置;另一个为文件结束指示器,当遇到文件尾时该指示器被设置。
20、流有3种不同的缓冲类型,它们是全缓冲、行缓冲和无缓冲。
21、进程在其生存期内可能处于三种基本状态:运行态、就绪态、等待态。
网络与信息安全管理员(4级)试题一、单选题(共60题,每题1分,共60分)1、在Linux系统中,()通常称为FIFO。
A、无名管道B、有名管道C、文件管道D、命名管道正确答案:D2、WireShark软件安装时可选安装的WinPcap软件的作用是()。
A、提供包过滤能力B、提供GUI界面C、提供底层的抓包能力D、增强抓包结果的分析能力正确答案:C3、()是传输层以上实现两个异构系统互连的设备。
A、路由器B、网桥C、网关D、集线器正确答案:A4、()是指攻击者在非授权的情况下,对用户的信息进行修改,如修改电子交易的金额。
A、非法使用攻击B、拒绝服务攻击C、信息泄漏攻击D、完整性破坏攻击正确答案:D5、网络犯罪的人一般具有较高的专业水平体现了互联网信息内容安全犯罪()的特点。
A、犯罪手段提升B、犯罪后果严重化C、犯罪主体专业化D、犯罪手段隐蔽化正确答案:C6、下列关于Botnet说法错误的是()。
A、用Botnet发动DDoS攻击B、Botnet的显著特征是大量主机在用户不知情的情况下,被植入了C、拒绝服务攻击与Botnet网络结合后攻击能力大大削弱D、Botnet可以被用来传播垃圾邮件、窃取用户数据、监听网络和扩正确答案:C7、来自网络的拒绝服务攻击可以分为停止服务和消耗资源两类。
攻击特点不包括以下哪个()。
A、多源性、特征多变性B、攻击目标与攻击手段多样性C、开放性D、隐蔽性正确答案:C8、计算机病毒的特性包括()。
A、传播性、破坏性、寄生性B、传染性、破坏性、可植入性C、破坏性、隐蔽性、潜伏性D、自我复制性、隐蔽性、潜伏正确答案:C9、TCSEC标准将计算机系统分为()个等级、7个级别。
A、4B、5C、6D、7正确答案:A10、上网收集与被害人、被害单位有关的负面信息,并主动联系被害人、被害单位,以帮助删帖、“沉底”为由,向其索取财物的行为,构成()。
A、诈骗罪B、诽谤罪C、侮辱罪D、敲诈勒索罪正确答案:D11、TCP/IP参考模型的四个层次分别为()、网际层、传输层、应用层。
填空题1、ARM微处理器有7种工作模式它们分为两类非特权模式、特权模式。
其中用户模式属于非特权模式2、ARM支持两个指令集,ARM核因运行的指令集不同,分别有两个状态ARM、Thumb,状态存放器CPSR的T位反映了处理器运行不同指令的当前状态3、ARM核有多个存放器,其局部用于通用存放器,有小局部作为专用存放器,R15存放器用于存储PC,R13通常用来存储SP。
ARM处理器有两种总线架构,数据和指令使用同一接口的是诺依曼,数据和收指令分开使用不同接口的是哈佛构造4、ARM微处理器复位后PC的地址通常是0*0初始的工作模式是Supervisor。
5、ARM微处理器支持虚拟存它是通过系统控制协处理器CP15和MMU存储管理部件来进展虚拟存的存储和管理。
当系统发生数据异常和指令领取异常时异常处理程序透过嵌入式操作系统的存管理机制通过MMU交换物理存和虚拟存的页面以保证程序正常执行。
6、编译代码时有两种存储代码和数据的字节顺序一种是小端对齐另一种是大端对齐。
7、构建嵌入式系统开发环境的工具链有多种其中开放源码的工具链是GNU工具链ARM公司提供的工具链是ADS工具链计算机有CISC和RISC两种类型以ARM微处理器为核心的计算机属于RISC 类型其指令长度是定长的9.一般而言嵌入式系统的构架可以分为4个局部分别是处理器、存储器、输入/输出和软件一般软件亦分为操作系统相关和应用软件两个主要局部。
10、根据嵌入式系统使用的微处理器可以将嵌入式系统分为嵌入式微控制器、嵌入式DSP 处理器、嵌入式微处理器以及片上系统。
11、操作系统是联接硬件与应用程序的系统程序,其根本功能有进程管理、进程间通信、存管理、I/O资源管理。
12、从嵌入式操作系统特点可以将嵌入式操作系统分为实时操作系统和分时操作系统其中实时系统亦可分为硬实时系统和软实时系统。
13、核负责管理各个任务或者为每个任务分配CPU时间并且负责任务之间的通信,核的根本效劳是任务切换。
QT进程间通信详细介绍及QProcess机制分析1、QT通信机制为了更好的实现QT的信息交互,在QT系统中创建了较为完善的通信机制。
QT的通信可分为QT内部通信和外部通信两大类。
对于这两类通信机制及应用场合做如以下分析:(1)QT内部对象间通信在图形用户界面编程中,经常需要将一个窗口部件的变化通知给窗口的其它部件使其产生相应的变化。
对于这种内部对象间的通信,QT主要采用了信号和槽的机制。
这种机制是QT区别于其他GUI工具的核心机制。
在大部分的GUI工具中,通常为可能触发的每种行为通过定义回调函数来实现。
这种回调函数是一个指向函数的指针,在进行函数回调执行时不能保证所传递的函数参数类型的正确性,因此容易造成进程的崩溃。
在QT中,信号和槽的机制取代了这种繁杂的、易崩溃的对象通信机制。
信号是当对象状态改变时所发出的。
槽是用来接收发射的信号并响应相应事件的类的成员函数。
信号和槽的连接是通过connect()函数来实现的。
例如,实现单击按钮终止应用程序运行的代码connect(button , SIGNAL(clicked()) , qApp , SLOT(quit()) );实现过程就是一个button被单击后会激发clicked信号,通过connect()函数的连接qApp会接收到此信号并执行槽函数quit()。
在此过程中,信号的发出并不关心什么样的对象来接收此信号,也不关心是否有对象来接收此信号,只要对象状态发生改变此信号就会发出。
此时槽也并不知晓有什么的信号与自己相联系和是否有信号与自己联系,这样信号和槽就真正的实现了程序代码的封装,提高了代码的可重用性。
同时,信号和槽的连接还实现了类型的安全性,如果类型不匹配,它会以警告的方式报告类型错误,而不会使系统产生崩溃。
(2)QT与外部设备间通信QT与外部通信主要是将外部发来的消息以事件的方式进行接收处理。
外部设备将主要通过socket与QT应用程序进行连接。
进程间通信和线程间通信的⼏种⽅式进程进程(Process)是计算机中的程序关于某数据集合上的⼀次运⾏活动,是系统进⾏资源分配和调度的基本单位,是结构的基础。
在早期⾯向进程设计的计算机结构中,进程是程序的基本执⾏实体;在当代⾯向线程设计的计算机结构中,进程是线程的容器。
程序是指令、数据及其组织形式的描述,进程是程序的实体。
进程是⼀个具有独⽴功能的程序关于某个数据集合的⼀次运⾏活动。
它可以申请和拥有系统资源,是⼀个动态的概念,是⼀个活动的实体。
它不只是程序的,还包括当前的活动,通过的值和处理的内容来表⽰。
进程的概念主要有两点:第⼀,进程是⼀个实体。
每⼀个进程都有它⾃⼰的地址空间,⼀般情况下,包括区域(text region)、数据区域(data region)和(stack region)。
⽂本区域存储处理器执⾏的代码;数据区域存储变量和进程执⾏期间使⽤的动态分配的内存;堆栈区域存储着活动过程调⽤的指令和本地变量。
第⼆,进程是⼀个“执⾏中的程序”。
程序是⼀个没有⽣命的实体,只有器赋予程序⽣命时(操作系统执⾏之),它才能成为⼀个活动的实体,我们称其为。
进程是具有⼀定独⽴功能的程序关于某个数据集合上的⼀次运⾏活动,进程是系统进⾏资源分配和调度的⼀个独⽴单位。
每个进程都有⾃⼰的独⽴内存空间,不同进程通过进程间通信来通信。
由于进程⽐较重量,占据独⽴的内存,所以上下⽂进程间的切换开销(栈、寄存器、虚拟内存、⽂件句柄等)⽐较⼤,但相对⽐较稳定安全。
线程线程是进程的⼀个实体,是CPU调度和分派的基本单位,它是⽐进程更⼩的能独⽴运⾏的基本单位.线程⾃⼰基本上不拥有系统资源,只拥有⼀点在运⾏中必不可少的资源(如程序计数器,⼀组寄存器和栈),但是它可与同属⼀个进程的其他的线程共享进程所拥有的全部资源。
线程间通信主要通过共享内存,上下⽂切换很快,资源开销较少,但相⽐进程不够稳定容易丢失数据。
⼀个线程可以创建和撤消另⼀个线程,同⼀进程中的多个线程之间可以并发执⾏。
linux信号量机制(semaphore)信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问。
当公共资源增加时,调用函数sem_post()增加信号量。
只有当信号量值大于0时,才能使用公共资源,使用后,函数sem_wait()减少信号量。
函数sem_trywait()和函数pthread_ mutex_trylock()起同样的作用,它是函数sem_wait()的非阻塞版本。
它们都在头文件/usr/include/semaphore.h中定义。
信号量的数据类型为结构sem_t,它本质上是一个长整型的数。
函数sem_init()用来初始化一个信号量。
它的原型为:extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));sem为指向信号量结构的一个指针;pshared不为0时此信号量在进程间共享,否则只能为当前进程的所有线程共享;value给出了信号量的初始值。
函数sem_post( sem_t *sem )用来增加信号量的值。
当有线程阻塞在这个信号量上时,调用这个函数会使其中的一个线程不在阻塞,选择机制同样是由线程的调度策略决定的。
函数sem_wait( sem_t *sem )被用来阻塞当前线程直到信号量sem的值大于0,解除阻塞后将sem的值减一,表明公共资源经使用后减少。
函数sem_trywait ( sem_t *sem )是函数sem_wait()的非阻塞版本,它直接将信号量sem的值减一。
函数sem_destroy(sem_t *sem)用来释放信号量sem。
例1:使用信号量。
例子中一共有4个线程,其中两个线程负责从文件读取数据到公共的缓冲区,另两个线程从缓冲区读取数据作不同的处理(加和乘运算)。
/* File sem.c */#include <stdio.h>#include <pthread.h>#include <semaphore.h>#define MAXSTACK 100int stack[MAXSTACK][2];int size=0;sem_t sem;/* 从文件1.dat读取数据,每读一次,信号量加一*/void ReadData1(void){FILE *fp=fopen("1.dat","r");while(!feof(fp)){fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);sem_post(&sem);++size;}fclose(fp);}/*从文件2.dat读取数据*/void ReadData2(void){FILE *fp=fopen("2.dat","r");while(!feof(fp)){fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);sem_post(&sem);++size;}fclose(fp);}/*阻塞等待缓冲区有数据,读取数据后,释放空间,继续等待*/ void HandleData1(void){while(1){sem_wait(&sem);printf("Plus:%d+%d=%d\n",stack[size][0],stack[size][1],stack[size][0]+stack[size][1]);--size;}}void HandleData2(void){while(1){sem_wait(&sem);printf("Multiply:%d*%d=%d\n",stack[size][0],stack[size][1],stack[size][0]*stack[size][1]);--size;}}int main(void){pthread_t t1,t2,t3,t4;sem_init(&sem,0,0);pthread_create(&t1,NULL,(void *)HandleData1,NULL);pthread_create(&t2,NULL,(void *)HandleData2,NULL);pthread_create(&t3,NULL,(void *)ReadData1,NULL);pthread_create(&t4,NULL,(void *)ReadData2,NULL);/* 防止程序过早退出,让它在此无限期等待*/pthread_join(t1,NULL);}在Linux下,用命令gcc -lpthread sem.c -o sem生成可执行文件sem。
Linux管道通信浅析作者:高霞曾辉邓谦来源:《数字化用户》2013年第26期【摘要】在Linux下,由于处于用户态的不同进程之间是彼此隔离的,它们必须通过某种机制来进行通信。
Linux平台下提供了多种进程通信方式,如管道、信号量、消息队列等,本文主要研究了Linux环境中的管道通信的实现机制,探讨无名管道和有名管道的工作方式,及相应的创建和使用的方法。
【关键词】Linux、进程通信、管道一、管道实现机制我们把从一个进程连接到另一个进程的数据流称为“管道”,这是最早的Linux进程间通信机制之一。
在Linux中管道常作为一种特殊文件处理。
实际上,管道是内核中一个固定大小的缓冲区,它按先进先出的方式进行数据传输,一个进程向管道中写的内容会被管道另一端的进程读出。
每次写入的内容都添加在管道缓冲区的末尾,且从缓冲区的头部读出数据,读写的位置自动增加,并且从管道读数据是一次性操作,数据一旦被读,便从管道中被抛弃。
在缓冲区写满时,则由相应的规则控制读写进程进入等待队列,当空的缓冲区有写入数据或满的缓冲区有数据读出时,就唤醒等待队列中的读写进程继续读写。
管道分无名管道和有名管道。
无名管道没有文件名,也没有磁盘节点,仅作为一个内存对象存在,用完后便销毁。
无名管道没有显式的打开过程,实际上它在创建时就自动打开了,故只能由有亲缘关系的两个进程间通信使用。
而有名管道克服了无名管道没有名字的限制,可由任意两个或多个进程间通信使用,它的使用方法和普通文件类似,都遵循打开、读、写、关闭的过程,只是读写的内部实现和普通文件有所不同。
二、无名管道(一)无名管道创建int pipe(int fd[2])在Linux中可以通过系统调用建立管道。
当一个管道建立时,会创建两个文件描述符fd [0]和fd [1],其中fd [0]固定用于读管道,fd[1]固定用于写管道,如图1所示,这样就构成了一个半双工通道。
由于管道用于不同进程间通信,而调用pipe()创建的管道两端处于一个进程中,这在实际应用中没有太大意义。
嵌⼊式系统-复习题资料⼀、1、某⽂件属性显⽰为 drwxr-xr-x,则该⽂件是( A )。
A、⽬录⽂件B、普通⽂件C、链接⽂件D、管道⽂件2、在linux中,通常作为⽤户⼯作⽬录的是( C )。
A、 /bootB、/etcC、 /homeD、/bin3、下列命令中,⽤于显⽰系统进程列表的命令是( D )。
A、 locateB、mvC、 catD、ps4、表⽰⽬标⽂件的扩展名⼀般是( B )。
A、.cB、 .oC、 .hD、 .i5、在Makefile的⼯程管理中,( C )表⽰第⼀个依赖⽂件的名称。
A、 $*B、$+C、$<D、 $?6、以下不属于嵌⼊式系统特点的是 B 。
A 、不具备⼆次开发能⼒B 、⾯向通⽤应⽤ C、软硬件裁剪 D、软件固化于芯⽚7、对嵌⼊式板进⾏在线交叉调试(ICD⽅式),所使⽤的连接接⼝⽅式为( D )。
A、USBB、⽹络接⼝C、串⼝D、 JTAG8、linux与开发板串⾏调试⽅式中,所使⽤到的⼯具软件是( A )A、 minicomB、超级终端C、arm-linux-gccD、 gdb9、在Linux内核源代码中,与处理器体系结构有关的⼦⽬录是( C )。
A、/includeB、/initC、/archD、drivers10、下列⽂件系统,不是嵌⼊式系统的⽂件系统格式的是( B )A、cramfsB、ntfsC、romfsD、jffs11、以下属于Linux⽂件系统格式的是( A )A、EXT3B、FATC、FAT32D、NTFS12、某⽂件属性显⽰为–rwxr-xr-x,则该⽂件是( B )。
A、⽬录⽂件B、普通⽂件C、链接⽂件D、管道⽂件13、在linux中,通常作为存放系统配置⽂件的⽬录是( B )。
A、 /bootB、/etcC、 /homeD、/bin14、下列命令中,⽤于给特定进程发送信号的命令是( C )。
A、 locateB、mvC、 killD、 cat15、在Makefile的⼯程管理中,( D )表⽰⽬标⽂件的完整名称。
嵌入式linux应用程序开发期末考试题库及答案一、判断题(正确的打“√”,错误的打“×”)【】1、学习嵌入式技术不需要硬件基础知识,只需要会软件编程即可。
【】2、Contex-M3系列处理器内核采用了哈佛结构。
【】3、我们学习所用的台式电脑及笔记本电脑属于嵌入式系统。
【】4、小明的手机能拍照并能保存照片,其手机内部芯片会利用到模数转换器。
【】5、嵌入式Linux操作系统属于免费的操作系统。
【】6、在嵌入式电子产品开发过程中我们要尽可能使用高档的嵌入式处理器。
【】7、嵌入式系统一般对低功耗要求不高。
【】8、windows XP 操作系统属于嵌入式操作系统。
【】9、在Linux C语言编程中,我们常用的编译器是GDB,调试器是GCC。
【】10、我们在新建一个makefile文件时,其文件名可以命名为Makefile或makefile。
【】11、Shell只是一种命令语言,不是属于程序设计语言。
【】12、Contex-M3系列处理器内核采用了冯·诺依曼结构。
【】13、#!/bin/bash 此句中的“#”的作用为注释。
【】14、一个shell脚本只有一种执行方式:./xxx.sh 。
【】15、嵌入式linux操作系统属于免费的操作系统。
【】16、进程是一个程序的一次执行的过程。
【】17、嵌入式系统一般对低功耗要求不高。
【】18、所有的电子设备都属于嵌入式设备。
【】19、移植操作系统时需要修改操作系统中与处理器直接相关的程序。
【】20、嵌入式开发需要专门的软件和硬件设备。
【】21、可以用touch命令创建一个新文件。
【】22、如果删除虚拟机里面的操作系统的系统文件将会影响外面主机的正常运行。
【】23、#!/bin/bash 此句中的“#”的作用为注释。
【】24、一个shell脚本只有一种运行方式:sh xxx.sh 。
【】25、在Linux中,一切都是文件。
【】26、线程是一个进程内的基本调度单位。
linux系统编程试卷(答案)凌阳教育嵌入式培训系统编程部分测试试题注:考试为闭卷,程序题需上机操作运行出结果,考试时间为120分钟一:选择题(本题共4小题,每题3分共12分)1)下列不是Linux系统进程类型的是( D )A 交互进程B 批处理进程C 守护进程D 就绪进程(进程状态)2)以下对信号的理解不正确的是( B )A 信号是一种异步通信方式B 信号只用在用户空间进程通信,不能和内核空间交互C 信号是可以被屏蔽的D 信号是通过软中断实现的3)进程有三种状态( C )A 准备态、执行态和退出态B 精确态、模糊态和随机态C 运行态、就绪态和等待态D 手工态、自动态和自由态4)不是进程和程序的区别( B)A 程序是一组有序的静态指令,进程是一次程序的执行过程B 程序只能在前台运行,而进程可以在前台或后台运行C 程序可以长期保存,进程是暂时的D 程序没有状态,而进程是有状态的二:填空题(本题共6小题,2)、3)两题每空四分,其余每空一分。
共23分)1) 列举八种常见的进程间通信方式无名管道、有名管道、消息队列、信号量、共享内存、信号、套接字网络上两个主机的进程间通信方式为套接字2) 命名管道比无名管道的优势提供了一个可以访问的路径名,实现没亲缘关系的进程间通信3) 消息队列比命名管道和无名管道的优势可以按类型实现消息的随机查询,没必要先进先出4) 按照逻辑结构不同进行数据库划分,Sqlite 数据库属于哪一类关系型数据库5) 在C语言中操作sqlite数据库,常用的2中方式是sqlite_exec(回调)、sqlite_gettable(非回调)6) 列举四种进程调度算法先来先调度(FCFS)、短进程优先调度(SPF)、高优先级调度(HPF)、时间片轮转调度三:问答题(本题共7题,每题5分,共35分)1) 什么是系统调用?系统调用是通过什么方式陷入内核态的?请写出你对系统调用的理解。
什么是文件I/O和标准I/O库?文件I/O和标准I/O库的区别?系统调用是指操作系统提供给用户程序调用的一组特殊接口,用户程序可以通过这组接口获得操作系统内核提供的服务。
嵌⼊式⾯试笔试题⽬——附部分答案1 、如何⾃动创建设备⽂件?class_create device_create2、led驱动编写有⼏种⽅式?输⼊⼦系统字符设备驱动总线platform led⼦系统3、如何实现http服务器?tcp服务器:socket4、如何编写守护进程,简述syslog的作⽤?第⼀步:创建进程、杀死⽗进程第⼆步:创建新的会话第三步:改变⼯作路径路径第四步:修改⽂件掩码权限第五步:关闭⽂件描述符5、bootloader和uboot的区别?bootloader是启动装载。
这是⼀段很⼩的程序,⽤于在系统上电启动初期运⾏,初始化关键接⼝,如内存,串⼝,关闭中断,关闭看门狗,引导系统进⼊内核的⼀段初始化的程序。
它主要任务就是将内核映像从硬盘读到RAM中,然后跳转到内核的⼊⼝点去运⾏内核,从⽽建⽴系统运⾏的必要环境。
uboot:是bootloader的⼀种6、如何移植uboot?1、下载源码2、解压uboot源码并进⼊⽬录3、指定交叉编译⼯具链4、指定产品BOARD 底板5、编译u-boot7、传感器驱动如何编写?8、BL0,BL1,BL2,BL3的作⽤?BL0 ⽂件是存放在 CPU 内部 IROM 中的⼀段固化代码,CPU 上点之后,⾸先去运⾏soc中的BL0,运⾏时会将 BL1 拷贝到 CPU 的 IRAM 中,然后执⾏BL1;BL1⽂件执⾏起来之后会先进⾏内存的初始化,之后将 BL2 ⽂件拷贝到外部内存中,BL2会初始化BL3的运⾏环境,将BL3搬移到DRAM中,BL3会有⼀个⾃搬移的过程,从⽽启动内核⼊⼝。
BL0:CPU内部的固化代码BL1:三星提供的加密⽂件BL2:截取uboot.bin 前14kBL3:剩下的uboot 执⾏命令以及加载引导内核9、exynos4412 时钟 APLL,MPLL,VPLL的区别?------倍频锁相环APLL:⽤于 CPU_BLK (可产⽣⾼达1.4GHz的频率);作为 MPLL 的补充,它也可以给DMC_BLK 、LEFTBUS_BLK 、RIGHTBUS_BLK 和 CMU_TOP 提供时钟。
IPC(进程间通信)详解Linux环境下,进程地址空间相互独⽴,每个进程各⾃有不同的⽤户地址空间。
任何⼀个进程的全局变量在另⼀个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据bi必须通过内核,在内核中开辟⼀块缓冲区,进程1把数据从⽤户空间放⾄内核缓冲区,进程2再从内核缓冲区把数据读⾛,内核提供的这种机制称为进程间通信(IPC InterProcess Communication)⼆、进程间通信的7种⽅式第⼀类:传统的Unix通信机制1. 管道/匿名管道(pipe)管道是半双⼯的,数据只能向⼀个⽅向流动;需要双⽅通信时,需要建⽴起两个管道。
只能⽤于⽗⼦进程或者兄弟进程之间(具有亲缘关系的进程);单独构成⼀种独⽴的⽂件系统:管道对于管道两端的进程⽽⾔,就是⼀个⽂件,但它不是普通的⽂件,它不属于某种⽂件系统,⽽是⾃⽴门户,单独构成⼀种⽂件系统,并且只存在与内存中。
数据的读出和写⼊:⼀个进程向管道中写的内容被管道另⼀端的进程读出。
写⼊的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
管道的实质:管道的实质是⼀个内核缓冲区,进程以先进先出的⽅式从缓冲区存取数据,管道⼀端的进程顺序的将数据写⼊缓冲区,另⼀端的进程则顺序的读出数据。
该缓冲区可以看做是⼀个循环队列,读和写的位置都是⾃动增长的,不能随意改变,⼀个数据只能被读⼀次,读出来以后在缓冲区就不复存在了。
当缓冲区读空或者写满时,有⼀定的规则控制相应的读进程或者写进程进⼊等待队列,当空的缓冲区有新数据写⼊或者满的缓冲区有数据读出来时,就唤醒等待队列中的进程继续读写。
管道的局限:管道的主要局限性正体现在它的特点上:只⽀持单向数据流;只能⽤于具有亲缘关系的进程之间;没有名字;管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配⼀个页⾯⼤⼩);管道所传送的是⽆格式字节流,这就要求管道的读出⽅和写⼊⽅必须事先约定好数据的格式,⽐如多少字节算作⼀个消息(或命令、或记录)等等;2. 有名管道(FIFO)匿名管道,由于没有名字,只能⽤于亲缘关系的进程间通信。
2011-06-08 21:45linux 管道 FIFO——写的很全,转来的pipe是Linux中最经典的进程间通信手段,在终端里通常用来组合命令,例如“ls -l|wc -l”。
它的作用很直观,就是使得前一个进程的输出作为后一个进程的输入,在概念上很符合“管道”的意思。
用管道实现“ls -l | wc -l”《情景分析》上有这个例子的代码,我觉得很适合用来了解管道。
这里假设终端对应的进程为PA,wc、ls是PA先后创建的两个子进程child_B与child_C。
代码简化后抄录如下:int main(){int pipefds[2], child_B, child_C;pipe(pipefds);if (!(child_B=fork()){ //先创建“读”的一端,它要关闭“写”的的一端close(pipefds[1]);close(0);dup2(pipefds[0], 0); //在执行系统调用execve后,child_B会释放0,1,2之外由父进程打开的文件,close(pipefds[0]); //所以要把pipefds[0]复制到标准输入对应的文件句柄0 execl("/usr/bin/wc", "-l", NULL);} //这里之后,A和B可以通过管道进行通信close(pipefds[0]);if (!(child_C=fork()){ //再创建“写”的一端,它要关闭“读”的的一端close(1);dup2(pipefds[1],1); //道理同前面close(pipefds[1]);execl("/bin/ls", "-1", NULL);} //这里之后,B和C可以通过管道进行通信close(pipefds[1]);wait4(child_B, NULL, 0, NULL);return 0;}FIFOFIFO就是命名管道,或有名管道。
对于pipe我们不难看出它只能用于一个进程家族之间通信,父子之间,兄弟之间等等。
如果想要让管道在更宽泛的环境中,那是不行的,原因是它没有“名字”或者说是匿名的,另外的进程看不到它,这样就有了命名管道。
它同样是基于VFS,对应的文件类型就是FIFO文件,可以通过mknod命令在磁盘上创建一个FIFO文件(注意:这就是它与pipe的本质区别,pipe完全就是存在与内存中,在磁盘上毫无痕迹),当进程想通过该FIFO 来通信时就可以标准的API open打开该文件,然后开始读写操作。
对于FIFO 的读写实现,它与pipe是相同的。
区别在于,FIFO有open这一操作,而pipe 是在调用pipe这个系统调用时直接创建了一对文件描述符用于通信。
并且,FIFO 的open操作还有些细致的地方要考虑,例如如果写者先打开,尚无读者,那么肯定是不能通信了,所以就需要先去睡眠等待读者打开该FIFO,反之对读者亦然。
管道是Linux中很重要的一种通信方式,是把一个程序的输出直接连接到另一个程序的输入,常说的管道多是指无名管道,无名管道只能用于具有亲缘关系的进程之间,这是它与有名管道的最大区别。
有名管道叫named pipe或者FIFO(先进先出),可以用函数mkfifo()创建。
Linux管道的实现机制在Linux中,管道是一种使用非常频繁的通信机制。
从本质上说,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件进行通信的两个问题,具体表现为:· 限制管道的大小。
实际上,管道是一个固定大小的缓冲区。
在Linux中,该缓冲区的大小为1页,即4K字节,使得它的大小不象文件那样不加检验地增长。
使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。
· 读取进程也可能工作得比写进程快。
当所有当前进程数据已被读取时,管道变空。
当这种情况发生时,一个随后的read()调用将默认地被阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。
注意:从管道读数据是一次性操作,数据一旦被读,它就从管道中被抛弃,释放空间以便写更多的数据。
1. 管道的结构在 Linux 中,管道的实现并没有使用专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。
通过将两个 file 结构指向同一个临时的VFS 索引节点,而这个 VFS 索引节点又指向一个物理页面而实现的。
2.管道的读写管道实现的源代码在fs/pipe.c中,在pipe.c中有很多函数,其中有两个函数比较重要,即管道读函数pipe_read()和管道写函数 pipe_wrtie()。
管道写函数通过将字节复制到 VFS 索引节点指向的物理内存而写入数据,而管道读函数则通过复制物理内存中的字节而读出数据。
当然,内核必须利用一定的机制同步对管道的访问,为此,内核使用了锁、等待队列和信号。
当写进程向管道中写入时,它利用标准的库函数write(),系统根据库函数传递的文件描述符,可找到该文件的 file 结构。
file 结构中指定了用来进行写操作的函数(即写入函数)地址,于是,内核调用该函数完成写操作。
写入函数在向内存中写入数据之前,必须首先检查 VFS 索引节点中的信息,同时满足如下条件时,才能进行实际的内存复制工作:·内存中有足够的空间可容纳所有要写入的数据;·内存没有被读程序锁定。
如果同时满足上述条件,写入函数首先锁定内存,然后从写进程的地址空间中复制数据到内存。
否则,写入进程就休眠在 VFS 索引节点的等待队列中,接下来,内核将调用调度程序,而调度程序会选择其他进程运行。
写入进程实际处于可中断的等待状态,当内存中有足够的空间可以容纳写入数据,或内存被解锁时,读取进程会唤醒写入进程,这时,写入进程将接收到信号。
当数据写入内存之后,内存被解锁,而所有休眠在索引节点的读取进程会被唤醒。
管道的读取过程和写入过程类似。
但是,进程可以在没有数据或内存被锁定时立即返回错误信息,而不是阻塞该进程,这依赖于文件或管道的打开模式。
反之,进程可以休眠在索引节点的等待队列中等待写入进程写入数据。
当所有的进程完成了管道操作之后,管道的索引节点被丢弃,而共享数据页也被释放。
因为管道的实现涉及很多文件的操作,因此,当读者学完有关文件系统的内容后来读pipe.c中的代码,你会觉得并不难理解。
Linux 管道的创建和使用都要简单一些,唯一的原因是它需要更少的参数。
实现与 Windows 相同的管道创建目标,Linux 和 UNIX 使用下面的代码片段:创建 Linux 命名管道int fd1[2];if(pipe(fd1)){ printf("pipe() FAILED: errno=%d",errno);return 1;}Linux 管道对阻塞之前一次写操作的大小有限制。
专门为每个管道所使用的内核级缓冲区确切为 4096 字节。
除非阅读器清空管道,否则一次超过 4K 的写操作将被阻塞。
实际上这算不上什么限制,因为读和写操作是在不同的线程中实现的。
Linux 还支持命名管道。
对这些数字的早期评论员建议我,为公平起见,应该比较 Linux 的命名管道和 Windows 的命名管道。
我写了另一个在 Linux 上使用命名管道的程序。
我发现对于 Linux 上命名的和未命名的管道,结果是没有区别。
Linux 管道比 Windows 2000 命名管道快很多,而 Windows 2000 命名管道比 Windows XP 命名管道快得多。
例子:#include<stdio.h>#include<unistd.h>int main(){int n,fd[2]; // 这里的fd是文件描述符的数组,用于创建管道做准备的pid_t pid;char line[100];if(pipe(fd)<0) // 创建管道printf("pipe create error\n");if((pid=fork())<0) //利用fork()创建新进程printf("fork error\n");else if(pid>0){ //这里是父进程,先关闭管道的读出端,然后在管道的写端写入“hello world"close(fd[0]);write(fd[1],"hello word\n",11);}else{close(fd[1]); //这里是子进程,先关闭管道的写入端,然后在管道的读出端读出数据n= read(fd[0],line,100);write(STDOUT_FILENO,line,n);}exit(0);}备注:管道分为无名管道和有名管道,其中无名管道不属于任何文件系统,只存在于内存中,它是无名无形的,但是可以把它看作一种特殊的文件,通过使用普通文件的read(),write()函数对管道进行操作,有名管道是有名有形的,为了使用这种管道,LINUX中设立了一个专门的特殊文件系统--管道文件,它存在于文件系统中,任何进程可以在任何时候通过有名管道的路径和文件名来访问管道。
但是在磁盘上的只是一个节点,而文件的数据则只存在于内存缓冲页面中,与普通管道一样。