码迷,mamicode.com
首页 > 编程语言 > 详细

用户级线程

时间:2016-04-29 17:59:58      阅读:186      评论:0      收藏:0      [点我收藏+]

标签:

线程的切换

在看进程切换前,我们先来看线程的切换吧。
这一篇主要说的是用户级线程的切换。
因为 进程的切换=资源切换+指令执行序列切换。
将资源和指令序列分开看,如果只是从一个执行指令序列切换到另一个执行指令序列,那么这就是线程的切换。

线程保留了并发(一个cpu上交替的执行多个程序)的优点,避免了进程切换代价,不需要切资源(映射表),只是切执行指令序列。线程切换的实质就是映射表不变而PC指针变。

用户级线程的切换

一个网页浏览器
一个线程用来从服务器接收数据
一个线程用来显示文本

开始实现这个游览器…

void WebExplorer()
{
    char URL[]="http://cms.hit.edu.cn";
    char buffer[1000];
    pthread_create(...,GetData,URL,buffer);
    pthread_create(...,Show,buffer);
}

void GetData(char* URL,char *p){...};
void Show(char* p){...};

我们下载了一段时间的数据后,切出去执行另一个线程,显示文本后,切回来继续下载。

技术分享

Yield与Create

pthread_create()让多个线程同时触发,yield()能完成线程的切换,使线程交替执行。

现在有两个执行序列,我们想要其中执行了一段时间后,跳到另一个去执行,之后又切回来。(线程的切换)
技术分享

技术分享

Yiled从100跳到300
技术分享

//B中的Yield
void Yield()
{
   找到300;
   jmp 300;
}
//D中的Yield
void Yield()
{
   找到204;
   jmp204;
}

两个执行序列与一个栈…

从100开始执行,在A函数中遇到B函数的调用,B的返回地址即下一句指令的地址104压栈,又在B中遇到Yield()调用,Yield()的返回地址204压栈。在B中的Yield()jmp到300,执行C函数,在C中遇到D()调用,304压栈,执行D(),遇到D中的Yield()调用,Yield()的返回地址404压栈。

技术分享

D中的Yield()执行后,跳到204

200:B()
{
   Yield();
   204:
}

204开始执行遇到”}”,会弹栈,栈顶元素404被弹出执行404,这里就出现问题了,我们刚才已经回到100那个线程了,现在却又切到了300那个线程。

所以两个序列一个栈是不行的。

一个栈到两个栈

每个序列对应一个栈,Yield切换先切栈。

技术分享

//D中的Yield
void Yield()
{
   TCB2.esp=esp;
   esp=TCB1.esp;
   jmp 204;
}

现在两个栈的情况是:

技术分享

执行D中的Yield,使栈完成了切换,esp=1000。但是遇到jmp 204,就跳到204,那么Yield()就永远不能返回了。

//D中的Yield
void Yield()
{
   TCB2.esp=esp;
   esp=TCB1.esp;
  //jmp 204;
}

把jmp 204去掉,此时栈已经完成了切换esp=1000,然后Yield执行遇到“}”,弹栈,此时弹栈弹出栈顶元素 204,执行204(“}”相当于ret),再ret,弹栈就是104了。

所以两个线程的样子:两个TCB、两个栈、切换的PC在栈中。

而ThreadCreate的核心就是申请一个栈,一个TCB(线程控制块),再将栈与TCB关联。

void ThreadCreate(A)
{
   TCB* tcb=malloc();
   *stack=malloc();
   *stack=A;//100 执行线程的起始地址
   tcb.esp=stack;//栈和TCB关联
}

综上

void ThreadCreate(func,arg1)
{
   申请栈;
   申请TCB;
   func等入栈;
   关联TCB与栈;
}
void GetData(char* URL,char *p)
{
   连接URL;
   下载;
   Yield();
   ...
}
void Yield()
{
   压入现场;
   esp放在当前TCB中;
   Next();//调度函数,对系统影响很大,可优先调度Show
   从下个TCB取出esp;
   弹栈切换线程;
}

用户级线程

因为这里的Yield,Create是用户程序,没有进入内核,所以说是用户级线程。
用户级线程对于内核是不可见的。
如果进程的某个线程进入内核并阻塞,对于内核来说,它是看不到那个进程里面有其他线程的,所以会直接切到别的进程去执行。此时用户级线程的并发性就没有什么用了。

例如

GetData()
{
  连接URL发起请求;
  等待网卡IO...
  进程阻塞
}
Show()
{
  显示文本和连接;
  ...
}

用户级线程只能在用户级切来切去,不进入内核。

技术分享

用户级线程

标签:

原文地址:http://blog.csdn.net/codetz/article/details/51244684

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!