Nanos-操作系统oslab1(2)---sleep和wakeup
来源:互联网 发布:淘宝买官换机哪家靠谱 编辑:程序博客网 时间:2024/06/05 16:26
目标:
这次要为进程实现sleep功能和wakeup功能,所以我们需要添加两个队列,一个是运行队列runningList,还有一个则是等待队列waitingList。
链表的使用
提供的链表节点结构如下:
typedef struct ListHead {ListHead *prev;ListHead *next;}ListHead;如何使用这个链表节点呢?毕竟平常创建的链表节点,里边可是会在节点定义里边添加value值的啊。
我们可以使用PCB和ListHead来新创建一个节点结构如下:
typedef struct PCBList{PCB *pcb; ListHead listNode;}PCBList;关于这个链表,它提供了以下几个函数,
链表节点的初始化,链表节点的加入
void list_init(ListHead *list){assert(list != NULL);list->prev = list;list->next = list;list->value = 0;}void list_add(ListHead *prev, ListHead *next, ListHead *data){assert(data != NULL);data->prev = prev;data->next = next;if (NULL != prev){prev->next = data;}if (NULL != next){next->prev = data;}}void list_add_before(ListHead *list, ListHead *data){assert(list != NULL);list_add(list->prev, list, data);}我看到这个双向链表节点的加入感觉好懵懵懂懂啊,新节点加入之后,链表结构到底是怎么变化的呢?
比如我首先创建一个头结点ListHead head,之后初始化它,那么我们的双向链表就是如下图所示:
加入一个节点之后呢?
ListHead node1;
list_init(node1);
list_add_before(&head, &node1);
我们知道会有这样的操作:
list_add(head->prev, &head, &node1)
也即node1->prev = head->prev;
node1->next = &head;
head->prev->next = node1;
head->prev = node1;
感觉好混乱啊,画个图来看看吧:
首先head的prev和next都是指向自己的,为了表示更加清晰,我们使用一个单独的head->prev节点,当然了,此时head->prev == head。
接着node1节点加入,然后就是按照上面写的修改指向,也就是此时的中间图。
因为head->prev和head节点时同一个节点,所以合并之后就变成第三幅图了。
那么我再加入一个节点node2情况会怎么样呢?
node2->prev = head->prev;
node2->next = &head;
head->prev->next = node2;
head->prev = node2;
初始情况如最左图,中间图显示指向关系的变化,蓝色为变化的指向,黑色为没有改变的指向,之后将head->prev节点与node1节点合起来就得到了最右图所示结果。
整个链表的遍历可以按照如下代码所示:
void list_traversal(){cout << "traverse in order:\t"; ListHead *node = head.next;while (node != &head){cout << node->value << "\t";node = node->next;}cout << endl;cout << "traverse in reverse order:"; node = head.prev;while (node != &head){cout << node->value << "\t";node = node->prev;}cout << endl;}所以对于2个节点和3个节点的示例,
ListHead node1, node2;list_init(&head);list_init(&node1);list_init(&node2);node1.value = 1;node2.value = 2;list_add_before(&head, &node1);list_traversal();list_add_before(&head, &node2);list_traversal();结果为:
两个队列的设计
测试用例
void A () { int x = 0; while(1) { if(x % 100000 == 0) { printk("a"); wakeup(PCB_of_thread_B); sleep(); } x ++; }}void B () { int x = 0; while(1) { if(x % 100000 == 0) { printk("b"); wakeup(PCB_of_thread_C); sleep(); } x ++; }}void C () { int x = 0; while(1) { if(x % 100000 == 0) { printk("c"); wakeup(PCB_of_thread_D); sleep(); } x ++; }}void D () { int x = 0; while(1) { if(x % 100000 == 0) { printk("d"); wakeup(PCB_of_thread_A); sleep(); } x ++; }}
根据create_kthread我们可以得到这4个函数的PCB,sleep()函数可以对宏current操作,而wakeup函数则需要对相应的PCB操作,所以我们定义4个全局变量PCB *来记录生成的四个PCB。
PCB *pPcbA = NULL;PCB *pPcbB = NULL;PCB *pPcbC = NULL;PCB *pPcbD = NULL;我们首先不考虑等待队列情况,首先将所有的4个线程都加入运行队列,然后测试看看效果如何。
- 生成4个线程的PCB
- 将这4个线程加入runningHead中
- 调度函数中轮询runningHead中的线程
生成4个线程的PCB
加入运行队列
很严重的问题1
调度函数
- 运行队列为空
- 运行队列不为空,但是current宏指向idle线程
- 运行队列不为空,current不指向idle
很严重的问题2
根据pNode得到PCB *
wakeup的设计
sleep的设计
- Nanos-操作系统oslab1(2)---sleep和wakeup
- PowermanagerService的sleep和wakeup流程
- android sleep and wakeup
- Nanos-南大操作系统实验1--线程切换
- android power managerment 之sleep and wakeup
- babyos2(16)—— sleep, wakeup
- Linux操作系统 sleep(0)、sleep(1)和sleep(-1)的区别,他们各有什么作用
- php对象serialize、unserialize时与sleep、wakeup的关系
- WinCE挂起和唤醒(suspend/wakeup)
- linux_2.6.35_wait和wakeup源码阅读
- linux_2.6.35_wait和wakeup源码阅读
- Sleep()和sleep()
- Linux操作系统常用命令之sleep
- 操作系统对sleep(1)影响
- 理解操作系统的sleep函数
- 多线程编程中的条件变量和虚假唤醒(spurious wakeup)
- 多线程中的条件变量和虚假唤醒(Spurious wakeup)
- 线程基础2—sleep和join
- Datatables之开篇
- 斐波那契数列
- 九宫格 GridView
- 两个类之间的消息机制
- 《黑客与画家》读书笔记2-关于“不能说的话”
- Nanos-操作系统oslab1(2)---sleep和wakeup
- 天声人語 20150609
- python多线程编程
- Java Socket编程
- Java泛型 类型擦除在继承中引入的问题及编译器的解决方法
- Linux下设置export JAVA_OPTS选项进行tomcat JVM内存设置【 linux下tomcat的参数JAVA_OPTS必须设在catalina.sh中cygwin=false前】
- ios学习笔记(一)Windows7上使用VMWare搭建iPhone开发环境
- 全局静态函数的定义和实现
- Java并发编程:Callable、Future和FutureTask