首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C 標準庫 setjmp/longjmp 實現協程機制:原理、陷阱與 ucontext 對比

     編輯:關於C

協程簡介

  • 協程 = 協作式多任務,單執行緒內多個進入點/暫停點函數。
  • 無搶佔調度開銷,切換僅涉及棟樑暫存器/棧指標交換。
  • Knuth:「子程式是協程的特例」。

setjmp/longjmp 機制

#include 
jmp_buf env;               // 保存 CPU 狀態(PC, SP, 通用暫存器等)

int setjmp(jmp_buf env);   // 首次調用返回 0,長跳轉返回非 0
void longjmp(jmp_buf env, int val); // 恢復 env 狀態,setjmp 返回 val

關鍵規則(違反即 UB)

  1. 必須先呼叫 setjmp,再呼叫 longjmp。
  2. longjmp 必須在 setjmp 所在函數尚未返回時調用(棟樑仍有效)。
  3. 嚴禁將 setjmp 封裝在輔助函數中(輔助函數返回後棟樑失效)。

正確範例

#include 
#include 

jmp_buf buf;

void second(void) {
    puts("second");
    longjmp(buf, 1);      // 跳回 main 的 setjmp
}

void first(void) {
    second();
    puts("first");        // 不會執行
}

int main(void) {
    if (setjmp(buf) == 0) first();
    else puts("main");    // longjmp 後執行這裡
    return 0;
}

輸出:second\nmain

錯誤封裝範例(UB)

int try(jmp_buf *b) { return setjmp(*b); }  // 錯誤!setjmp 在 try 棟樑
void throw(jmp_buf *b) { longjmp(*b, 1); }   // 呼叫時 try 已返回,棟樑無效

ucontext 對比

現代建議

  • C++20 原生 coroutine(co_await)。
  • C 語言專案:優先考慮狀態機或 libco/libtask 成熟庫。
  • 教學/嵌入式極簡場景可用 setjmp,嚴守規則。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
特性setjmp/longjmpucontext (POSIX)
標準C89/C99POSIX.1-2001 (已移除 POSIX.1-2008)
功能非局部跳轉完整上下文切換(含信號遮罩)
協程庫基礎早期 libtask, protothreadslibco, libucontext, boost.coroutine
可移植性極高Unix-like,Windows 需模擬