# Pthreads,第 1 部分:簡介
> 原文:<https://github.com/angrave/SystemProgramming/wiki/Pthreads%2C-Part-1%3A-Introduction>
## 線程簡介
## 什么是線程?
線程是“執行線程”的縮寫。它表示 CPU 具有(并將執行)的指令序列。要記住如何從函數調用返回,并存儲自動變量和參數的值,線程使用棧。
## 什么是輕量級過程(LWP)?它與線程有什么關系?
好吧,對于所有意圖和目的,線程是一個過程(意味著創建一個線程類似于`fork`),除了**沒有復制**意味著沒有寫入副本。這允許進程共享相同的地址空間,變量,堆,文件描述符等。
創建線程的實際系統調用類似于`fork`;這是`clone`。我們不會詳細說明,但您可以閱讀[手冊頁](http://man7.org/linux/man-pages/man2/clone.2.html),請記住它不在本課程的直接范圍內。
LWP 或線程更傾向于分配許多場景,因為創建它們的開銷要少得多。但在某些情況下(特別是 python 使用它)多處理是使代碼更快的方法。
## 線程的棧如何工作?
您的主要功能(以及您可能調用的其他功能)具有自動變量。我們將使用棧將它們存儲在內存中,并使用簡單的指針(“棧指針”)跟蹤棧的大小。如果線程調用另一個函數,我們將棧指針向下移動,這樣我們就有更多的空間用于參數和自動變量。一旦從函數返回,我們就可以將棧指針移回其先前的值。我們保留舊棧指針值的副本 - 在棧上!這就是為什么從函數返回非常快 - 很容易“釋放”自動變量使用的內存 - 我們只需要更改棧指針。

在多線程程序中,有多個棧但只有一個地址空間。 pthread 庫分配一些棧空間(在堆中或使用主程序棧的一部分)并使用`clone`函數調用在該棧地址處啟動線程。總地址空間可能看起來像這樣。

## 我的進程可以有多少個線程?
您可以在進程內運行多個線程。你免費得到第一個帖子!它運行你在'main'中編寫的代碼。如果需要更多線程,可以使用 pthread 庫調用`pthread_create`創建新線程。您需要將指針傳遞給函數,以便線程知道從哪里開始。
您創建的線程都存在于同一個虛擬內存中,因為它們是同一進程的一部分。因此,他們都可以看到堆,全局變量和程序代碼等。因此,您可以在同一個進程內同時處理兩個(或多個)CPU。由操作系統決定將線程分配給 CPU。如果你有比 CPU 更多的活動線程,那么內核會將線程分配給 CPU 很短的時間(或直到它用完了要做的事情),然后自動切換 CPU 在另一個線程上工作。例如,一個 CPU 可能正在處理游戲 AI 而另一個線程正在計算圖形輸出。
## 簡單用法
## 你好世界 pthread 的例子
要使用 pthread,您需要包含`pthread.h`并且需要使用`-pthread`(或`-lpthread`)編譯器選項進行編譯。此選項告訴編譯器您的程序需要線程支持
要創建線程,請使用函數`pthread_create`。這個函數有四個參數:
```c
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
```
* 第一個是指向一個變量的指針,該變量將保存新創建的線程的 id。
* 第二個是指向屬性的指針,我們可以使用它來調整和調整 pthreads 的一些高級功能。
* 第三個是指向我們想要運行的函數的指針
* 第四個是指向我們的函數的指針
論點`void *(*start_routine) (void *)`很難讀懂!它表示一個指針,它接受一個`void *`指針并返回一個`void *`指針。它看起來像一個函數聲明,除了函數的名稱用`(* .... )`包裝
這是最簡單的例子:
```c
#include <stdio.h>
#include <pthread.h>
// remember to set compilation option -pthread
void *busy(void *ptr) {
// ptr will point to "Hi"
puts("Hello World");
return NULL;
}
int main() {
pthread_t id;
pthread_create(&id, NULL, busy, "Hi");
while (1) {} // Loop forever
}
```
如果我們想等待我們的線程完成使用`pthread_join`
```c
void *result;
pthread_join(id, &result);
```
在上面的例子中,`result`將是`null`,因為 busy 函數返回`null`。我們需要傳遞結果地址,因為`pthread_join`將寫入指針的內容。
見 [Pthreads 第 2 部分](https://github.com/angrave/SystemProgramming/wiki/Pthreads%2C-Part-2%3A-Usage-in-Practice)
- UIUC CS241 系統編程中文講義
- 0. 簡介
- #Informal 詞匯表
- #Piazza:何時以及如何尋求幫助
- 編程技巧,第 1 部分
- 系統編程短篇小說和歌曲
- 1.學習 C
- C 編程,第 1 部分:簡介
- C 編程,第 2 部分:文本輸入和輸出
- C 編程,第 3 部分:常見問題
- C 編程,第 4 部分:字符串和結構
- C 編程,第 5 部分:調試
- C 編程,復習題
- 2.進程
- 進程,第 1 部分:簡介
- 分叉,第 1 部分:簡介
- 分叉,第 2 部分:Fork,Exec,等等
- 進程控制,第 1 部分:使用信號等待宏
- 進程復習題
- 3.內存和分配器
- 內存,第 1 部分:堆內存簡介
- 內存,第 2 部分:實現內存分配器
- 內存,第 3 部分:粉碎堆棧示例
- 內存復習題
- 4.介紹 Pthreads
- Pthreads,第 1 部分:簡介
- Pthreads,第 2 部分:實踐中的用法
- Pthreads,第 3 部分:并行問題(獎金)
- Pthread 復習題
- 5.同步
- 同步,第 1 部分:互斥鎖
- 同步,第 2 部分:計算信號量
- 同步,第 3 部分:使用互斥鎖和信號量
- 同步,第 4 部分:臨界區問題
- 同步,第 5 部分:條件變量
- 同步,第 6 部分:實現障礙
- 同步,第 7 部分:讀者編寫器問題
- 同步,第 8 部分:環形緩沖區示例
- 同步復習題
- 6.死鎖
- 死鎖,第 1 部分:資源分配圖
- 死鎖,第 2 部分:死鎖條件
- 死鎖,第 3 部分:餐飲哲學家
- 死鎖復習題
- 7.進程間通信&amp;調度
- 虛擬內存,第 1 部分:虛擬內存簡介
- 管道,第 1 部分:管道介紹
- 管道,第 2 部分:管道編程秘密
- 文件,第 1 部分:使用文件
- 調度,第 1 部分:調度過程
- 調度,第 2 部分:調度過程:算法
- IPC 復習題
- 8.網絡
- POSIX,第 1 部分:錯誤處理
- 網絡,第 1 部分:簡介
- 網絡,第 2 部分:使用 getaddrinfo
- 網絡,第 3 部分:構建一個簡單的 TCP 客戶端
- 網絡,第 4 部分:構建一個簡單的 TCP 服務器
- 網絡,第 5 部分:關閉端口,重用端口和其他技巧
- 網絡,第 6 部分:創建 UDP 服務器
- 網絡,第 7 部分:非阻塞 I O,select()和 epoll
- RPC,第 1 部分:遠程過程調用簡介
- 網絡復習題
- 9.文件系統
- 文件系統,第 1 部分:簡介
- 文件系統,第 2 部分:文件是 inode(其他一切只是數據...)
- 文件系統,第 3 部分:權限
- 文件系統,第 4 部分:使用目錄
- 文件系統,第 5 部分:虛擬文件系統
- 文件系統,第 6 部分:內存映射文件和共享內存
- 文件系統,第 7 部分:可擴展且可靠的文件系統
- 文件系統,第 8 部分:從 Android 設備中刪除預裝的惡意軟件
- 文件系統,第 9 部分:磁盤塊示例
- 文件系統復習題
- 10.信號
- 過程控制,第 1 部分:使用信號等待宏
- 信號,第 2 部分:待處理的信號和信號掩碼
- 信號,第 3 部分:提高信號
- 信號,第 4 部分:信號
- 信號復習題
- 考試練習題
- 考試主題
- C 編程:復習題
- 多線程編程:復習題
- 同步概念:復習題
- 記憶:復習題
- 管道:復習題
- 文件系統:復習題
- 網絡:復習題
- 信號:復習題
- 系統編程笑話