<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] ## 概述 https://zhuanlan.zhihu.com/p/254883122 ## 前期知識準備 1. 現代操作系統是分時操作系統,資源分配的基本單位是進程,CPU調度的基本單位是線程。 2. C++程序運行時會有一個運行時棧,一次函數調用就會在棧上生成一個record 3. 運行時內存空間分為全局變量區(存放函數,全局變量),棧區,堆區。棧區內存分配從高地址往低地址分配,堆區從低地址往高地址分配。 4. 下一條指令地址存在于指令寄存器IP,ESP寄存值指向當前棧頂地址,EBP指向當前活動棧幀的基地址。 5. 發生函數調用時操作為:將參數從右往左依次壓棧,將返回地址壓棧,將當前EBP寄存器的值壓棧,在棧區分配當前函數局部變量所需的空間,表現為修改ESP寄存器的值。 6. 協程的上下文包含屬于他的棧區和寄存器里面存放的值。 ## 何時掛起,喚醒協程? 如開始介紹時所說,協程是為了使用異步的優勢,異步操作是為了避免IO操作阻塞線程。那么協程掛起的時刻應該是當前協程發起異步操作的時候,而喚醒應該在其他協程退出,并且他的異步操作完成時。 ## 如何掛起、喚醒協程,如何保護協程運行時的上下文? 協程發起異步操作的時刻是該掛起協程的時刻,為了保證喚醒時能正常運行,需要正確保存并恢復其運行時的上下文。 所以這里的操作步驟為: * 保存當前協程的上下文(運行棧,返回地址,寄存器狀態) * 設置將要喚醒的協程的入口指令地址到IP寄存器 * 恢復將要喚醒的協程的上下文 ### 什么是上下文切換 即使是單核CPU也支持多線程執行代碼,CPU通過給每個線程分配CPU時間片來實現這個機制。時間片是CPU分配給各個線程的時間,因為時間片非常短,所以CPU通過不停地切換線程執行,讓我們感覺多個線程時同時執行的,時間片一般是幾十毫秒(ms)。 CPU通過時間片分配算法來循環執行任務,當前任務執行一個時間片后會切換到下一個任務。但是,在切換前會保存上一個任務的狀態,以便下次切換回這個任務時,可以再次加載這個任務的狀態,從任務保存到再加載的過程就是一次上下文切換。 ### 線程上下文切換和進程上下文切換的區別 進程切換分兩步 1.切換頁目錄以使用新的地址空間 2.切換內核棧和硬件上下文。 對于`linux`來說,線程和進程的最大區別就在于地址空間。 對于線程切換,第1步是不需要做的,第2是進程和線程切換都要做的。所以明顯是進程切換代價大 線程上下文切換和進程上下問切換一個最主要的區別是線程的切換虛擬內存空間依然是相同的,但是進程切換是不同的。這兩種上下文切換的處理都是通過操作系統內核來完成的。內核的這種切換過程伴隨的最顯著的性能損耗是將寄存器中的內容切換出。 另外一個隱藏的損耗是上下文的切換會擾亂處理器的緩存機制。簡單的說,一旦去切換上下文,處理器中所有已經緩存的內存地址一瞬間都作廢了。還有一個顯著的區別是當你改變虛擬內存空間的時候,處理的頁表緩沖(processor’s Translation Lookaside Buffer (TLB))或者相當的神馬東西會被全部刷新,這將導致內存的訪問在一段時間內相當的低效。但是在線程的切換中,不會出現這個問題。 ### 上線文切換的實質 大概的切換流程如下: ``` 1. X86 32 Bists 2. SS --> 選擇子--->段描述表-->(段限,段基址) 3. CR3 --->頁目錄,頁表 4. ESP--> 5. EBP--> ``` 這其實和參數傳遞有點相似,只需要傳遞地址就夠了。 `ESP,EBP` 正式 堆棧指針寄存器。 變量通過`ESP,EBP` 兩個指針 加偏移量訪問。 ## 開始動手制作一個協程庫 業內實現的C/C++協程基本都采用`非對稱`的協程方式。 glibc庫的`context` ``` getcontext() : 獲取當前context setcontext() : 切換到指定context makecontext() : 設置 函數指針 和 堆棧 到對應context保存的sp和pc寄存器中,調用之前要先調用 getcontext() swapcontext() : 保存當前context,并且切換到指定context ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看