# 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 使用它)多处理是使代码更快的方法。
## 线程的栈如何工作?
您的主要功能(以及您可能调用的其他功能)具有自动变量。我们将使用栈将它们存储在内存中,并使用简单的指针(“栈指针”)跟踪栈的大小。如果线程调用另一个函数,我们将栈指针向下移动,这样我们就有更多的空间用于参数和自动变量。一旦从函数返回,我们就可以将栈指针移回其先前的值。我们保留旧栈指针值的副本 - 在栈上!这就是为什么从函数返回非常快 - 很容易“释放”自动变量使用的内存 - 我们只需要更改栈指针。
![](https://img.kancloud.cn/8d/0f/8d0fbbc8fef15386075590882d286dad_271x306.jpg)
在多线程程序中,有多个栈但只有一个地址空间。 pthread 库分配一些栈空间(在堆中或使用主程序栈的一部分)并使用`clone`函数调用在该栈地址处启动线程。总地址空间可能看起来像这样。
![](https://img.kancloud.cn/fc/b5/fcb5f793a316935114936560fdefb88a_459x391.jpg)
## 我的进程可以有多少个线程?
您可以在进程内运行多个线程。你免费得到第一个帖子!它运行你在'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 编程:复习题
- 多线程编程:复习题
- 同步概念:复习题
- 记忆:复习题
- 管道:复习题
- 文件系统:复习题
- 网络:复习题
- 信号:复习题
- 系统编程笑话