成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

揭秘操作系統最核心技術:進程與線程是如何一步步發明出來的?

系統
今天我想跟你聊聊一個計算機發展史上的精彩故事——進程與線程是如何一步步被發明出來的。

今天我想跟你聊聊一個計算機發展史上的精彩故事——進程與線程是如何一步步被發明出來的?

讓我帶你穿越時光隧道,看看這些關鍵概念是如何從無到有,最終成為現代操作系統基石的。

一、"一人獨占"的早期計算機時代

想象一下 20 世紀 50 年代的計算機實驗室:一臺體積龐大、價格昂貴的 UNIVAC 或 IBM 704 計算機占據了整個房間。這些早期計算機每次只能執行一個程序,用戶必須排隊等候。

更令人沮喪的是,當程序在等待磁帶或打印機等慢速設備時,這些價值不菲的計算機就會閑置著——就像一輛豪華跑車被迫停在路邊等待紅燈一樣浪費!

這種運行方式被稱為"批處理系統"。用戶把程序和數據打在卡片上交給操作員,然后等待——可能是幾個小時,甚至是整整一天!如果前面的程序出了 bug 導致死循環,后面所有人都只能干等。

有一天,麻省理工學院的計算機科學家 Fernando Corbató 盯著實驗室里的計算機發呆,突然靈光一閃:

"為什么要讓昂貴的計算機資源在等待慢速 I/O 操作時空閑呢?我們應該讓它能同時處理多個任務!"

二、分時系統:打破"獨占"的第一步

于是,Corbató 和他的團隊開始研發全新的系統——CTSS(Compatible Time-Sharing System,兼容分時系統),這被認為是現代多任務操作系統的雛形。

CTSS 的核心理念很簡單:在內存中同時加載多個程序,當一個程序等待 I/O 操作時,CPU 可以切換去執行另一個程序。這就是"多道程序設計"的開端。

但問題來了:如何讓一個正在運行的程序暫停,然后在未來某個時刻恢復執行呢?

答案是:必須保存程序的"上下文"信息!就像你在讀一本書時,如果要暫時去做別的事,你需要記住當前讀到第幾頁第幾行,這樣回來才能繼續讀。

于是,調查研究后,Corbató 和他的團隊設計出了一個關鍵的數據結構來保存程序的"狀態快照":

struct cpu_state {
    uint32_t r0, r1, r2, r3;         // 通用寄存器
    uint32_t pc;                     // 程序計數器
    uint32_t sp;                     // 棧指針
    uint32_t status;                 // 狀態寄存器
    // 其他必要的寄存器狀態...
};

有了這個結構,當系統需要切換任務時,就可以保存當前程序的所有寄存器狀態,然后加載另一個程序的狀態,讓 CPU 繼續執行新的程序。

三、內存保護:解決程序"打架"問題

但實施分時系統后,一個新問題很快浮出水面。在貝爾實驗室工作的 Dennis Ritchie(C 語言和 UNIX 的創始人之一)回憶道,他們的早期系統經常崩潰,而且數據會莫名其妙地被修改。

調查后,他們發現了根本原因:

不同的程序在同一內存空間中互相干擾!

原因很簡單:在早期系統中,所有程序共享同一塊內存空間,沒有任何隔離機制。就像幾個小孩在同一張紙上畫畫,互相涂抹對方的作品一樣混亂。

看看這個災難性的例子:

// 計費程序 : interest.c  
struct account {
    char name[50];
    double balance;
} customer = {"Zhang San", 1000.0};

void update_balance() {
    while(1) {
        customer.balance *= 1.05;  // 計算利息
        sleep(1);
    }
}

// 同時運行的取款程序 : withdraw.c
struct account {
    char name[50];
    double balance;
} customer = {"Zhang San", 1000.0};

void withdraw() {
    while(1) {
        customer.balance -= 100;  // 定期取款
        sleep(1);
    }
}

在早期系統中,由于缺乏地址空間隔離機制,這兩個獨立編譯的程序使用了相同的內存地址范圍,導致它們的 customer 變量實際上重疊在物理內存的同一區域,結果就是一個程序計算利息增加余額,另一個程序同時在取款減少余額,導致完全不可預測的結果。

系統科學家們意識到,必須從根本上解決這個問題——需要在操作系統層面提供內存隔離機制!

四、進程的誕生:給每個程序一個"隔離艙"

1964年,MIT、貝爾實驗室和通用電氣公司聯合開發了 MULTICS 系統。在這個過程中,一個革命性的概念誕生了——"進程"。

什么是進程?簡單說,進程就是一個運行中的程序實例,擁有獨立的內存空間和系統資源。

MULTICS 的設計者創建了一個內存映射系統,確保每個進程都有自己的獨立內存區域:

struct mem_layout {
    void* text_begin;        // 代碼區起始地址
    size_t text_size;        // 代碼區大小
    void* heap_begin;        // 堆區起始地址
    size_t heap_size;        // 堆區大小
    // 其他內存區域...
};

將這個結構與前面的狀態快照結構結合起來,就形成了完整的進程定義:

struct task_control {
    struct cpu_state registers;  // CPU狀態
    struct mem_layout memory;    // 內存布局
    pid_t id;                    // 任務標識符
    uint8_t state;               // 任務狀態
    resource_list_t resources;   // 資源列表
    // ... 其他控制信息
};

這就是操作系統中"進程控制塊"(PCB)的雛形!有了它,操作系統就能管理多個進程的執行,實現真正的多任務處理。

但這又帶來了新問題:如何公平地分配 CPU 時間給多個進程?

五、時間片輪轉調度:讓每個人都有發言權

在多進程系統中,如果讓一個進程一直運行到結束,其他進程就得一直等待,這顯然不合理。特別是對于交互式程序,用戶會感覺系統反應遲鈍。

為解決這個問題,MIT 的研究人員設計了一種全新的調度算法——"時間片輪轉調度"(Round-Robin Scheduling)。

這個概念非常簡單:給每個進程分配一個固定長度的 CPU 使用時間(稱為"時間片",通常為幾十毫秒),當一個進程用完自己的時間片,操作系統就強制將 CPU 分配給下一個等待的進程。

// 時間片輪轉調度的偽代碼
void scheduler() {
    while(true) {
        process = get_next_process_from_queue();
        set_timer(TIME_SLICE);  // 設置時鐘中斷
        context_switch(process); // 切換到該進程
        // 時間片用完后,時鐘中斷處理程序會調用scheduler()
    }
}

這就像是一場公平的會議,每個人都有固定的發言時間。即使有人滔滔不絕,到時間也必須讓下一位發言。

時間片的長度設置很有講究:

  • 太短:進程切換開銷占比太大,系統效率降低
  • 太長:響應時間變長,用戶體驗差

典型的時間片長度是 10-100 毫秒,這對人類感知來說足夠短,讓用戶感覺多個程序在"同時"運行,這就是我們熟悉的"并發"。

進程的誕生和時間片輪轉調度帶來了巨大的好處:

  • 不同程序之間徹底隔離,不會相互干擾
  • 系統可以同時運行多個程序,大大提高了效率
  • 即使一個程序崩潰,也不會影響其他程序的運行
  • 所有進程都能獲得公平的 CPU 使用時間

就像給每個畫畫的小孩分發獨立的畫紙,再也不用擔心誰會涂抹誰的作品了!同時,每個小孩都能輪流使用那支珍貴的金色畫筆(CPU)。

六、進程間通信與切換瓶頸

隨著進程模型的普及,新的需求出現了——進程之間需要交換數據和協調行動。UNIX的創始人們發明了各種"進程間通信"(IPC)機制,如 管道、消息隊列和共享內存等。

但隨著系統中運行的進程越來越多,一個嚴重的問題浮出水面——進程切換的開銷實在太大了!每次切換進程,系統都需要:

  • 保存當前進程的struct cpu_state(所有寄存器狀態)
  • 更新struct mem_layout(切換完整的內存映射)—— 最耗時
  • 刷新 TLB 緩存和其他處理器緩存
  • 恢復新進程的struct cpu_state

這個過程就像一名攝影師在拍攝多個場景之間切換:不僅要記住每個場景的拍攝角度和相機設置(CPU 狀態),還要搬運和重新布置整套燈光裝備、背景和道具(內存映射)。即使攝影師技術再好,這種場景切換的時間成本也是無法避免的!

在加州大學伯克利分校,研究人員還觀察到一個有趣的現象:服務器應用程序創建了大量進程來處理不同的請求,這些進程運行完全相同的代碼,卻各自占用獨立的內存空間。這簡直是在浪費資源!

面對這個問題,他們提出了一個革命性的疑問:"如果多個任務需要執行相同的程序代碼,為何不創造一種新機制,讓它們共享代碼和數據,只在需要時保持獨立?"

七、線程的誕生:輕量級的執行單元

1979年,Xerox PARC 的研究人員 David Boggs 和 Butler Lampson 在開發 Alto 操作系統時,提出了一個革命性的想法——"線程"。

線程被設計為進程內的"輕量級執行單元",它們:

  • 共享所屬進程的代碼段、數據段和系統資源
  • 擁有自己的執行棧和寄存器狀態
  • 可以獨立調度執行
struct execution_flow {
    uint32_t flow_id;         // 流ID
    uint8_t status;           // 運行狀態
    struct cpu_state regs;    // 寄存器狀態
    void *stack;              // 棧空間
    struct task_control *owner;  // 所屬任務
};

線程相比進程有哪些優勢?太多了!

  • 創建和銷毀更快:不需要分配新的地址空間,只需要一個新的棧
  • 切換開銷小:線程間切換不需要切換地址空間,速度提升好多倍!
  • 資源共享自然:同一進程的線程共享內存,可以直接讀寫共享變量
  • 通信簡單高效:線程間通信不需要特殊的IPC機制

就像網絡游戲中的"組隊"功能——同一隊伍的玩家可以共享地圖信息,直接交流,而不同隊伍之間則需要特殊渠道才能通信。

八、實戰對比:進程vs線程

理論講完了,來看個簡單例子,直觀感受進程與線程的區別:

多進程版web服務器:

import os
from http.server import HTTPServer, BaseHTTPRequestHandler

def run_server(port):
    server = HTTPServer(('', port), BaseHTTPRequestHandler)
    server.serve_forever()

# 創建5個進程,每個監聽不同端口
for i in range(5):
    pid = os.fork()  # 創建新進程
    if pid == 0:  # 子進程
        run_server(8000 + i)
        break# 子進程不再繼續循環

# 父進程需要等待子進程(簡化處理)
# ...

多線程版web服務器:

import threading
from http.server import HTTPServer, BaseHTTPRequestHandler

def run_server(port):
    server = HTTPServer(('', port), BaseHTTPRequestHandler)
    server.serve_forever()

# 創建5個線程,每個監聽不同端口
threads = []
for i in range(5):
    t = threading.Thread(target=run_server, args=(8000 + i,))
    threads.append(t)
    t.start()

# 等待所有線程結束
for t in threads:
    t.join()

# ...

代碼看起來很相似,但背后的區別巨大:

  • 多進程版本中,每個服務器進程有完全獨立的內存空間,資源消耗更大
  • 多線程版本中,所有線程共享同一個進程的內存空間,資源利用更高效
  • 多進程版更適合需要隔離的任務,多線程版更適合共享數據的任務

九、線程安全與未來趨勢

線程雖然解決了很多問題,但也帶來了新的挑戰,最大的就是"線程安全"問題。由于多個線程共享同一地址空間,并發訪問共享數據會導致"競態條件"。

看一個經典的計數器問題:

// 全局共享變量
int counter = 0;

// 線程函數
void* increment_counter(void* arg) {
    for (int i = 0; i < 100000; i++) {
        counter++;  // 實際上是: 讀取counter, +1, 寫回counter
    }
    return NULL;
}

當兩個線程同時執行時,最終 counter 值可能小于期望的 200000,因為線程可能同時讀取相同的值,各自加 1 后寫回,導致一個增量丟失。

為了解決這個問題,操作系統引入了各種同步原語,如互斥鎖、條件變量和信號量等。

技術永遠在進化。如今,新一代的并發模型已經出現:協程(Coroutine)比線程更輕量,由程序自己控制切換,不需要操作系統介入。

歷史回顧與結語

回顧這段歷史,我們看到了計算機從"一臺機器只能做一件事"到"同時處理成千上萬任務"的驚人進化:

  • 批處理系統(1950s):一次只運行一個程序,如早期的 IBM 704
  • 分時系統(1961):MIT 的 CTSS 首次實現了多用戶時間共享
  • 進程(1964):MULTICS 系統引入進程概念,為程序提供獨立執行環境
  • 線程(1979):Xerox Alto 操作系統引入輕量級執行單位,共享進程資源
  • 協程(2010s):用戶態的輕量級線程,進一步降低并發開銷

這就像交通工具從"一次只載一個人的獨木舟",逐步發展為如今的"高速磁懸浮列車"一樣神奇。

每當你打開電腦,運行十幾個應用程序,同時瀏覽網頁、聽音樂、下載文件,這一切看似理所當然的便利,都是幾代計算機科學家智慧的結晶。

進程和線程,這兩個看似抽象的概念,讓我們的數字生活變得如此豐富多彩。下次當你的電腦同時運行多個應用時,別忘了感謝那些 60 年代的工程師們——正是他們的創新思維,讓今天的多任務處理成為可能!

責任編輯:趙寧寧 來源: 跟著小康學編程
相關推薦

2025-04-03 01:45:00

2025-03-28 09:39:15

CPU指令信號

2025-04-30 04:20:00

操作系統虛擬內存

2024-09-30 09:56:59

2024-11-11 10:28:33

操作系統Unix系統

2024-09-12 10:04:06

內存程序系統

2010-03-04 16:28:17

Android核心代碼

2018-07-13 15:36:52

2024-06-27 08:30:36

內存擴容堆區

2024-08-30 08:30:29

CPU操作系統寄存器

2017-01-19 21:08:33

iOS路由構建

2017-12-25 11:50:57

LinuxArch Linux

2024-08-06 09:29:54

程序機器指令字符串

2019-03-05 14:09:27

Docker存儲容器

2019-07-09 15:23:22

Docker存儲驅動

2018-12-24 10:04:06

Docker存儲驅動

2019-04-01 10:15:02

2016-11-02 18:54:01

javascript

2017-01-06 15:13:25

LinuxVim源代碼

2015-07-27 16:06:16

VMware Thin虛擬化
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品免费看 | 免费一区二区三区 | 日韩欧美在线视频一区 | 国产精品国产三级国产aⅴ浪潮 | 国产伊人久久久 | 亚州毛片 | 日日久 | 蜜桃在线播放 | 中文字幕精品一区二区三区精品 | 中文字幕爱爱视频 | 精品无码三级在线观看视频 | 天堂一区在线观看 | 91精品国产777在线观看 | 欧美日韩在线观看一区 | 国产精品123区 | 久久免费看 | 国产精品一区一区三区 | 国产欧美在线一区 | av在线一区二区三区 | 欧美黄在线观看 | 国产精品久久久久久久久免费樱桃 | 日韩亚洲视频 | 欧美一级淫片免费视频黄 | 龙珠z在线观看 | 欧美综合一区二区 | 中文字幕亚洲一区二区三区 | 极品销魂美女一区二区 | 爱操av | 一区二区视频在线 | 九九色综合 | 欧美成人免费在线 | 国产视频二区 | 视频一区二区中文字幕 | 亚洲欧美日韩一区二区 | 久久久激情| 色综合天天综合网国产成人网 | 欧美成人一区二区三区 | 国产精品国产精品国产专区不蜜 | 视频一区二区在线观看 | 国产一区二区三区在线看 | 在线看片网站 |