作者:不想脱发的基兄
专栏:《嵌入式面试》
格言:不要老叹息过去,它是不再回来的;要明智地改善现在。要以不忧不惧的坚决意志投入扑朔迷离的未来。
2022年秋招我面试嵌入式MCU开发方向,经过了多场的笔试与面试,在准备的过程中看了非常多的资料,我的汇总的笔记一直写在有道云笔记中,没有分享出来。现在已经到了23年春招了,特此整理后分享出来。资料看过了觉得不错就保存下来了,如果有不对的地方,欢迎批评指正,侵权联删!
(1)volatile修饰的全局变量
Linux系统中的线程间通信方式主要以下几种:
(2)信号量(有名和无名信号量,执行PV操作)
(3)互斥锁(锁机制)
(4)读写锁(锁机制)
(5)条件变量(锁机制,互斥锁的一个加强)
信号量、互斥锁、读写锁、条件变量
(1)信号量:P/V操作,只要信号量大于0就可以P(需要同步的时候)
(2)互斥锁:互斥操作,使用不当容易死锁(临界资源保护一般考虑)
(3)读写锁:使用基本和互斥锁一样,区别是上锁的时候两种方式(临界资源的读操作比较多)
(4)条件变量:对互斥锁的一个加强,,他必须跟互斥锁一起配合使用。当某个条件产生的时候才能做某件事情(不是所有情况下,线程都能通过上互斥锁访问临界资源,而是有一定要求的时候。)
无名管道、有名管道(FIFO)、高级管道、信号量、信号、消息队列、共享内存、网络套接字。
(1)无名管道( pipe ): 管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
(2)高级管道(popen): 将另一个程序当做一个新的进程在当前程序进程中启动,则它算是当前程序的子进程,这种方式我们成为高级管道方式。
(3)有名管道(named pipe): 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
(4)消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
(5)信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
(6)信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
(7)共享内存( shared memory ) : 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
(8)套接字( socket ) : 套解字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信。
执行态、就绪态、浅睡眠态、深睡眠态、停止态、僵尸态、死亡态
(1)执行态(RUNNING):进程正在占有CPU。
(2)就绪态(RUNNING): 进程处于等待队列中等待调度。
(3)浅睡眠(INTERRUPTABLE):此时进程在等待一个事件的发生或某种系统资源,可响应信号。
(4)深睡眠(UNINTERRUPTABLE):此时进程在等待一个事件的发生或某种系统资源,无法响应信号。
(5)停止态(STOPPED):此时进程被暂停。
(6)僵尸态(ZOMBIE):此时进程不能被调度,但是PCB未被释放。
(7)死亡态(DEAD):是一个已终止的进程,且PCB将会被释放。
当不同线程对同一函数访问的时候,返回结果一致,就是可重入函数。否则就是不可重入函数。
(1)因为函数内部使用了共享资源,比如全局变量、环境变量。
(2)因为函数内部调用了其他不可重入函数。
(3)因为函数执行结果与某硬件设备相关。
(1)不使用任何静态数据,只使用局部变量或者堆内存。
(2)不调用任何非线程安全的不可重入函数。
线程池是一种多线程的处理形式,处理过程中将任务添加到队列中,然后再创建线程后自动启动这些任务。
(1)进程是系统中资源分配的基本单位,线程是系统任务调度的基本单位。
(2)进程是具有一定独立功能的程序、它是系统进行资源分配和调度的一个独立单位,重点在系统调度和单独的单位,也就是说进程是可以独立运行的一段程序。
(3)线程是进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源。在运行时,只是暂用一些计数器、寄存器和栈。
(1)fork():
1)父子进程的执行次序不确定。
2)子进程拷贝父进程的地址空间,子进程是父进程的一个复制品。
(2)vfork()函数:
1)保证子进程先运行,在它调用 exec(进程替换) 或 exit(退出进程)之后父进程才可能被调度运行。
2)子进程共享父进程的地址空间(准确来说,在调用 exec(进程替换) 或 exit(退出进程) 之前与父进程数据是共享的)。
vfork()函数和fork()函数一样都是在已有的进程中创建一个新的进程,但它们创建的子进程是有区别的。
如果进程运行时,父进程先去世,则子进程的父进程会变成祖进程,从而导致PID和PPID可能会改变。
(1)通信数据只存在于内存缓冲页面中;
(2)都是半双工通信。
区别 | 无名管道 | 有名管道 |
---|---|---|
名字 | 无名 | 有名 |
进程通信 | 父子进程或兄弟进程之间(亲缘进程)的通信 | 任意两进程之间通信 |
存储 | 有形,inode (索引)结点在磁盘上 | 无形,节点不是在磁盘上存储的,而是临时生成的 |
默认主函数打印的是主线程的错误码。
每一个线程的错误码私有。
wait函数用于等待子进程结束,回收并释放子进程资源。
(1)用于等待其他线程结束:当调用 pthread_join() 时,当前线程会处于阻塞状态,直到被调用的线程结束后,当前线程才会重新开始执行。
(2)对线程的资源进行回收:如果一个线程是非分离的(默认情况下创建的线程都是非分离)并且没有对该线程使用 pthread_join() 的话,该线程结束后并不会释放其内存空间,这会导致该线程变成了“僵尸线程”。
死锁,是指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,它们都将无法再向前推进。
(1)互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
(2)请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
(3)不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
(4)环路等待条件:在发生死锁时,必然存在一个进程–资源的环形链。
条件 | 说明 |
---|---|
破坏请求条件 | 资源一次性分配:一次性分配所有资源,这样就不会再有请求了 |
破坏请保持条件 | 只要有一个资源得不到分配,也不给这个进程分配其他的资源 |
破坏不可剥夺条件 | 可剥夺资源:即当某进程获得了部分资源,但得不到其它资源,则释放已占有的资源 |
破坏环路等待条件 | 资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反 |
参考链接
死锁产生的4个必要条件?
【嵌入式面试】2022年嵌入式经典面试题汇总(C语言)
【嵌入式面试】2022年嵌入式经典面试题汇总(数据结构)
【嵌入式面试】2022年嵌入式经典面试题汇总(Linux | 文件IO)