Linux嵌入式开发常见面试题

2019-07-12 14:18发布

what is the difference between mutex and spin_lock"

两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是
自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该
自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。

同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。  
异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。

UART是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现全双工传输和接收。在嵌入
式设计中,UART用来主机与辅助设备通信

SPI是串行外设接口(Serial Peripheral Interface)的缩写。SPI,是一种高速的,全双工,同步的
通信总线,并且在芯片的管脚上只占用四根线,

I2C总线(I2C bus,Inter-IC bus)是一个双向的两线连续总线,同步通信方式,提供集成电路(ICs)
之间的通信线路。I2C总线是一种串行扩展技术

what is the difference between open and fopen
1.fopen have a buffer,open not have a buffer.
2.fopen是ANSIC标准中的C语言库函数,返回的是文件结构的指针,文件描述符
3.open 系统调用,返回的是文件句柄
认为fopen和open最主要的区别是fopen在用户态下就有了缓存,在进行read和write的时候减少了
用户态和内核态的切换,而open则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文
件,fopen系列的函数要比直接调用open系列快;如果随机访问文件open要比fopen快

what is the difference between fork and thread?
我们从Linux内核的角度去分析,两者是没有区别的。从用户空间去分析两者是有区别的。主要区别在于
存储代码的结构。
每个进程在创建时额外申请了新的内存空间以及存储代码段、数据段、BSS段、堆、栈空间,并且初始化
为父进程空间的值,父子进程在创建后不能互访对方资源。
每个创建新的线程在用户空间仅申请自己的栈空间而与桐进程的其他线程共享其他的地址空间,包括
码段、数据段、BSS段、堆、栈。

指针与引用区别

值传递:

形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单
向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改
变影响调用者时,采用值传递。

指针传递:
形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作

引用传递:
形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形
式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的
地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参
变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
★ 相同点:
1. 都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。

★ 区别:
1. 指针是一个实体,而引用仅是个别名;
2. 引用使用时无需解引用(*),指针需要解引用;
3. 引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”
4. 引用没有 const,指针有 const,const 的指针不可变;
5. 引用不能为空,指针可以为空;
6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的
变量或对象的地址)的大小;typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,
但是当引用作为成员时,其占用空间与指针相同(没找到标准的规定)。
7. 指针和引用的自增(++)运算意义不一样;

TCP与UDP的区别?
TCP:传输控制协议,面向连接,可靠,三次握手协议,TCP传输慢
UDP:用户数据报协议,无连接,不可靠,UDP传输速度快
基于TCP的协议有:HTTP/HTTPS,Telnet,FTP,SMTP。
基于UDP的协议有:DHCP,DNS,SNMP,TFTP,BOOTP

------管道

管道的优点是不需要加锁,缺点是默认缓冲区太小,只有4K,同时只适合父子进程间通信,而且一个管道只适合单向通信,如果要双向通信需要建立两个。而且不适合多个子进程,因为消息会乱,它的发送接收机制是用read/write这种适用流的,缺点是数据本身没有边界,需要应用程序自己解释,而一般消息大多是一个固定长的消息头,和一个变长的消息体,一个子进程从管道read到消息头后,消息体可能被别的子进程接收到

------消息队列

消息队列也不要加锁,默认缓冲区和单消息上限都要大一些,在我的suse10上是64K,它并不局限于父子进程间通信,只要一个相同的key,就可以让不同的进程定位到同一个消息队列上,它也可以用来给双向通信,不过稍微加个标识,可以通过消息中的type进行区分,比如一个任务分派进程,创建了若干个执行子进程,不管是父进程发送分派任务的消息,还是子进程发送任务执行的消息,都将type设置为目标进程的pid,因为msgrcv可以指定只接收消息类型为type的消息,这样就实现了子进程只接收自己的任务,父进程只接收任务结果

------共享内存

共享内存的几乎可以认为没有上限,它也是不局限与父子进程,采用跟消息队列类似的定位方式,因为内存是共享的,不存在任何单向的限制,最大的问题就是需要应用程序自己做互斥,有如下几种方案

1 只适用两个进程共享,在内存中放一个标志位,一定要声明为volatile,大家基于标志位来互斥,例如为0时第一个可以写,第二个就等待,为1时第一个等待,第二个可以写/读

2 也只适用两个进程,是用信号,大家等待不同的信号,第一个写完了发送信号2,等待信号1,第二个等待信号2,收到后读取/写入完,发送信号1,它不是用更多进程是因为虽然父进程可以向不同子进程分别发送信号,但是子进程收到信号会同时访问共享内存,产生不同子进程间的竞态条件,如果用多块共享内存,又存在子进程发送结果通知信号时,父进程收到信号后,不知道是谁发送,也意味着不知道该访问哪块共享内存,即使子进程发送不同的结果通知信号,因为等待信号的一定是阻塞的,如果某个子进程意外终止,父进程将永远阻塞下去,而不能超时处理

3 采用信号量或者msgctl自己的加锁、解锁功能,不过后者只适用于linux
内存操作相关参考:http://blog.csdn.net/qq_21792169/article/details/52732772