我是天才
伟大的野心家,实践家; 程序员,技术问题解决者.

导航

 

无意中受libtask启发看到getcontext这函数,一下子学得我应该能自己写一个用户级线程库了. 

以前做个课程设计时写嵌入式操作系统内核,也写过进程调用的东西.

看到getcontext函数后,我又想练练手了.getcontext把最难搞的保存上下文信息弄好了。

若是自己写必须用汇编,还必须了解对应硬件体系结构的东西

有几个难点要处理:

1.栈大小不够时,如何自动增长?

2.是抢占式的还是协同式的?

采用不可剥夺,协同方式进行线程切换。因为在用户级上采用不可剥夺效率会更高。而且用户应该知道更合理的时机进行切换。提供task_yield函数

 

栈增长的方向要注意,应该是向下的.而数组的增长方向是向上的.

线程的数据结构组织方面

给一个tid,如何直接得到对应的task* ?

存一个task*的数组all,这样就可以通过tid直接得到对应的线程控制结构了.

ready队列搞一个.利用链表把就绪队列管理起来

freeslot分配task*的糟位

最后整个程序退出时要释放task,如何编历到所有分配的资源? 先把free_slot链表的所有都置为NULL,然后扫描一遍all,对不为NULL的项进行释放。

task_create流程:
分配结构体的空间
初始化成员,包括context
放到ready队列中
 
schedule流程:
死循环
从ready队列中取一项作为running,如果没有ready的了,准备退出
进行swapcontext切换到running的上下文
返回这里意味running做了上下文切换,可能原因是主动yield,读写channel而block,以及线程退出
如果原因是该task要退出,则释放资源
把running置为NULL
 
task_exit流程:
把task的status置为EXITING。要switch到schedule中才能真正释放空间,因为task_exit函数使用的是此task的栈。
把对应的slot回收给free_slot
进行swapcontext换到schedule的上下文
 
task_yield流程:
把当前running挂到ready队列
swapcontext到schedule的上下文
 
线程通信方面。只支持channel
channel中分别挂着阻塞队列(数组),因无法写管道而阻塞的挂在sender,因读管道阻塞的挂在receiver。队列的每个元素就是struct task*
不单独设置block队列
管道可以是带缓存的也可以不是带缓存的。不带的用void *p
带的有个数组实现的环形队列
 
chan_send流程:
确定是否能写管道
若不能写,将当前线程挂到此通道的sender链中,然后swap到schedule_context进行调度
若可写,则写管道,然后从receiver中挑一个放到ready队列
然后函数返回0表示此函数调用没有被阻塞过
 
非阻塞IO
用户级线程,假如其中用个线程IO阻塞了,则整个进程也会被阻塞
如何解决这个问题?让某个线程IO阻塞后调度器自动切到其它线程继续运行?
核心思想:将IO的文件描述符设置为非阻塞,然后专门开一个后台线程做epoll
fd设置为不阻塞 fdnoblock
fd_read中,若error==EAGAIN则调用fdwait
fdwait函数把fd加到pollfd中,然后切换线程
开一个fdtask线程专程检测就绪的pollfd,此线程的流程:
无限循环:
while(task_yield() > 0);    //确定没有其它task运行时才做IO
if(poll(pollfd,npollfd,ms) < 0) {  //有可运行的fd
    for 每个可运行的线程
        调用task_ready
posted on 2012-08-06 13:40  Genius0101  阅读(1473)  评论(0)    收藏  举报