yield函数是并发编程中非常重要的概念,要完成“同时”程序,必须利用yield函数,特别是在多核计算机不那么流行的时代。
yield意味着“屈服、礼节”,在程序中表示为当前线程尽可能让出CPU资源让其他线程执行,yield函数背后发生了什么? 结合线程和堆栈说明函数背后是如何执行的,程序是如何配合CPU完成yield函数的。
让我们先看一个例子,
100:A () (b ); 104:}200:B () { yield ); 204:}300:C () (d ); 304:}400:D () { yield ); 404:yeald ()找到了吗? 跳? } 12345678910112131415161718192021上的代码。 总体来说,说明了a (),b ) )在某个线程正在执行中,c ) ),d ) )在另一个线程正在执行中,运行到b ) )函数时,调用yield从a线程跳到b线程执行
如果我们这样设计就可以了吗?
两个线程共享一个堆栈。 pc指向100,a线程进入a (函数并开始执行,b )在进入函数之前堆栈指针104,在执行b函数之后立即遇到yeld函数,堆栈204,a线程停止执行,yeld停止b线程此时,yield函数希望我们的本意是返回a线程,只运行204。 这个时候,弹堆栈,弹404。 这是错误的。 我们不是要跑204吗?
您可以看到两个线程共享一个堆栈。 使用yield函数无法达到我们想要的效果。 设计者们认识到,实际上进程中的线程模型和进程操作系统中的模型在几个方面是相似的。 一个线程应该与堆栈对应并与其他线程隔离,就像进程对应于被隔离的内存区域一样。 这样,当我们从a线程跳转到b线程执行时,CPU必须跳转时,需要记录a线程的相关信息并执行b线程,然后用相关信息再次跳转到a线程执行。 这是我们学习的PCB (
多个线程维护各自的堆栈是非常伟大的迁移,很多线程的操作变得清晰。
yield () { TCB2.esp=esp; esp=TCB1.esp; }上面的yield函数才是实际上从b线程跳转到a线程执行的操作,可以清楚地看到堆栈操作执行的顺序。 Thread control block线程控制块可以理解为由进程管理的数据结构。 此数据结构包含有关线程的信息,其中一个字段是esp,它是当前线程的堆栈指针。 回到上面的函数,可以看到,esp位于CPU寄存器的指针所指向的位置,yield函数实际上存储当前CPU正在执行的线程的堆栈,检索要执行的线程的堆栈指针,并将其分配给寄存器以开始执行。
现在显而易见,当a线程跳转到b线程时,在a线程堆栈中,104 204被前后堆栈,跳转到b线程之后,304 405被前后推入当前线程的堆栈中,从而切换寄存器的堆栈指针这时弹一下堆栈,继续执行204,一切就会变得完美。
之后,每个线程都有地址和变量进出堆栈,线程不断分离,完成了我们设计的“同时”程序。
版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。