1. 程序中断方式
1.1 程序中断方式例题
2. 总结
3. DMA方式
3.1 DMA控制器
3.2 DMA传送过程
3.3 DMA传送方式
3.4 DMA方式的特点
3.5 DMA方式与中断方式
3.6 DMA方式与中断方式对CPU占用情况
3.7 总结
3.8 单链表面试题代码实现
// 面试题1:
// 获取单链表有效节点的个数
public static int getLength(HeroNode head) {
if (head.next == null)
return 0;
int cnt = 0;
// 不记头节点
HeroNode cur = head.next;
while (cur != null) {
cnt++;
cur = cur.next;
}
return cnt;
}
// 面试题2:
// 查找单链表中的倒数第k个节点
// 注意判断k的值是否不合法,或者超过了链表本身的长度!
public static HeroNode getBottomNode(HeroNode head, int k)
{
int length = getLength(head);
if(length == 0)
{
System.out.println("该链表为空!");
return null;
}
if(k<=0 || k>length)
{
System.out.println("输入的节点序号不合法或者超越链表本身长度!");
return null;
}
HeroNode cur = head.next;
for(int i=0; i<(length-k); i++)
{
cur = cur.next;
}
return cur;
}
// 面试题3:
// 反转单链表
public static void reverseList(HeroNode head)
{
if(head.next==null || head.next.next==null)
System.out.println("该链表无需反转!");
HeroNode reversedHead = new HeroNode(0, "", "");
HeroNode cur = head.next;
HeroNode next = null;
while(cur != null)
{
next = cur.next;
cur.next = reversedHead.next;
reversedHead.next = cur;
cur = next;
}
// 这里不能写成head = reversedHead的原因是出了这个方法后就失效了,链表的反转只能在该方法的局部作用域实现!
head.next = reversedHead.next;
}
// 面试题4:
// 逆序打印单链表而不破坏其结构
public static void reversePrinting(HeroNode head)
{
if(head.next==null)
return;
Stack<HeroNode> stack = new Stack<>();
HeroNode cur = head.next;
while(cur != null)
{
stack.push(cur);
cur = cur.next;
}
while(stack.size()>0)
System.out.println(stack.pop());
}
// 面试题5:合并两个单链表,并使元素编号按升序排列
public static SingleLinkedList mergedList(HeroNode head1, HeroNode head2)
{
SingleLinkedList target = new SingleLinkedList();
HeroNode head = target.getHead();
HeroNode cur1 = head1.next;
HeroNode cur2 = head2.next;
HeroNode next1 = null;
HeroNode next2 = null;
while(cur1 != null && cur2 != null)
{
if(cur1.no < cur2.no)
{
if(cur1.next != null)
{
next1 = cur1.next;
cur1.next = null;
target.add(cur1);
cur1 = next1;
}
else
{
target.add(cur1);
cur1 = cur1.next;
}
}
else if(cur2.no < cur1.no)
{
if(cur2.next != null)
{
next2 = cur2.next;
cur2.next = null;
target.add(cur2);
cur2 = next2;
}
else
{
target.add(cur2);
cur2 = cur2.next;
}
}
}
if(cur1 != null)
{
while(cur1 != null)
{
if(cur1.next != null)
{
next1 = cur1.next;
cur1.next = null;
target.add(cur1);
cur1 = next1;
}
else
{
target.add(cur1);
cur1 = cur1.next;
}
}
}
else if(cur2 != null)
{
while(cur2 != null)
{
if(cur2.next != null)
{
next2 = cur2.next;
cur2.next = null;
target.add(cur2);
cur2 = next2;
}
else
{
target.add(cur2);
cur2 = cur2.next;
}
}
}
return target;
}
总结
1. 聊聊I/O接口和I/O端口的区别?
接口负责连接CPU以及外设,CPU同外设进行信息传送的实质是对接口内的端口寄存器进行读写操作。常见的端口有状态端口(读),控制端口(写),数据端口(读写)。
2. 聊聊你知道的中断系统?
I/O方式有程序查询方式,程序中断方式以及DMA方式,其中程序中断方式中应用到了中断系统。其中中断系统的工作流程有中断请求、中断响应和中断处理。中断处理的过程又分中断隐指令以及中断服务程序。
中断隐指令的主要任务有关中断、保存断点以及引出中断服务程序。关中断的作用是保证CPU主要寄存器中的内容,以免被新的中断打断。保存断点是为了保证在I/O工作完毕后能重新回到原来的断点。引出中断服务程序的作用是在中断服务程序准备好后将中断服务程序的入口地址传送给CPU控制器内的PC寄存器。
中断服务程序的主要任务有保护现场,中断服务,恢复现场以及中断返回。保护现场是保存程序断点PC(已在中断隐指令中完成),并且保存通用寄存器和状态寄存器的内容。中断服务,通过程序使其能达到外设的缓冲存储器中。恢复现场的作用是把之前的信息送回CPU寄存器,并且读取之前保存的PC断点。中断返回的作用是让程序能继续正常工作。
3. 聊聊你知道的DMA方式与中断方式这两种I/O方式?它们的优缺点又分别是什么?
只要CPU不进行访存的时候DMA方式就能正常运行,对于中断请求来说,中断方式的中断请求是在CPU指令执行周期结束后响应中断,对于DMA方式的中断请求是对I/O设备完成对应的操作后进行中断的后处理。中断方式可以处理异常事件,而DMA方式仅能传送数据。虽然DMA方式的预处理和后处理的总时钟周期开销大于中断方式,但是DMA传送块的大小远远大于中断方式传送信息的大小,因此DMA方式占用CPU比率远远小于中断方式。
4. 注意单链表反转中的核心:
next = cur.next;
cur.next = reversedHead.next;
reversedHead.next = cur;
cur = cur.next;
以及为什么最后一定要是
head.next = reversedHead.next;(作用域问题,不能写成head = reversedHead!)