Skip to content

Commit

Permalink
修改
Browse files Browse the repository at this point in the history
  • Loading branch information
arkingc committed Jul 3, 2018
1 parent 4705785 commit 423b7c0
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 29 deletions.
52 changes: 26 additions & 26 deletions 操作系统/UNIX环境高级编程.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@

* [六.线程](#六线程)
- [1.相关函数](#1相关函数)
+ [pthread_create函数](#1pthread_create函数)
+ [pthread_join函数](#2pthread_join函数)
+ [pthread_self函数](#3pthread_self函数)
+ [pthread_detach函数](#4pthread_detach函数)
+ [pthread_exit函数](#5pthread_exit函数)
+ [pthread_equal函数](#6pthread_equal函数)
+ [pthread_cancel函数](#7pthread_cancel函数)
- [2.线程同步](#2线程同步)
+ [2.1 互斥锁](#21-互斥锁)
+ [2.2 读写锁](#22-读写锁)
Expand Down Expand Up @@ -2522,14 +2529,6 @@ struct tms{
## 1.相关函数

* [pthread_create函数](#1pthread_create函数)
* [pthread_join函数](#2pthread_join函数)
* [pthread_self函数](#3pthread_self函数)
* [pthread_detach函数](#4pthread_detach函数)
* [pthread_exit函数](#5pthread_exit函数)
* [pthread_equal函数](#6pthread_equal函数)
* [pthread_cancel函数](#7pthread_cancel函数)

### 1)pthread_create函数

该函数用于创建一个POSIX线程。**当一个程序由exec启动执行时,称为“初始线程”或“主线程”的单个线程就创建了。其余线程则由pthread_create函数创建**
Expand Down Expand Up @@ -2883,7 +2882,6 @@ Single UNIX Specification还提供了下列版本:
<div align="center"> <img src="../pic/apue-thread-9.png"/> </div>

* **pthread_cond_wait**函数等待`cond`指向的条件变量,投入睡眠之前会释放`mutex`指向的互斥锁,唤醒后会重新获得`mutex`指向的互斥锁
*
* **pthread_cond_timewait**在给定的时间内等待条件发生,超时会重新获取`mutex`指向的互斥锁并返回一个错误码(这个时间仍然是一个绝对时间)

两个函数成功返回时,线程需要重新计算条件,因为另一个线程可能已经在运行并改变了条件
Expand Down Expand Up @@ -2919,13 +2917,13 @@ Single UNIX Specification还提供了下列版本:
* **pthread_spin_trylock**:如果不能获取锁,就立即返回`EBUSY`错误
* **pthread_spin_unlock**:对自旋锁解锁。如果试图对没有加锁的自旋锁进行解锁,结果是未定义的

**在持有自旋锁时,不要调用可能会进入休眠状态的函数。如果调用了这些函数,会浪费CPU资源,因为其他线程需要获取自旋锁需要等待的实际就延长了**
**在持有自旋锁时,不要调用可能会进入休眠状态的函数。如果调用了这些函数,会浪费CPU资源,因为其他线程需要获取自旋锁需要等待的时间就延长了**

### 2.5 屏障

**屏障是用户协调多个线程并行工作的同步机制。屏障允许每个线程等待,直到所有的合作线程都到达某一点,然后从改点继续执行**
**屏障是用户协调多个线程并行工作的同步机制。屏障允许每个线程等待,直到所有的合作线程都到达某一点,然后从该点继续执行**

`pthread_join`就是一种屏障,允许一个线程等待,直到另一个线程退出
> `pthread_join`就是一种屏障,允许一个线程等待,直到另一个线程退出
### 1)屏障的初始化与销毁

Expand Down Expand Up @@ -3084,14 +3082,14 @@ pthread_attr_destroy(&attr);

新旧状态的设置是一个原子操作

`pthread_cancel`调用并不等待线程终止。默认情况下,线程在取消请求发出后还是继续运行,直到线程到达某个取消点。取消点是线程检查它是否被取消的一个位置,POSIX.1保证线程调用下列函数时,取消点都会出现:
`pthread_cancel`调用并不等待线程终止。**默认情况下,线程在取消请求发出后还是继续运行,直到线程到达某个取消点**。取消点是线程检查它是否被取消的一个位置,POSIX.1保证线程调用下列函数时,取消点都会出现:

<div align="center"> <img src="../pic/apue-threadctr-24.png"/> </div>

可取消状态可以是下面的值:

* `PTHREAD_CANCEL_ENABLE`:默认值
* `PTHREAD_CANCEL_DISABLE`:对`pthread_cancel`的调用并不会杀死线程。相反,取消请求对这个线程来说还处于挂起状态,当取消状态再次变为`PTHREAD_CANCEL_ENABLE`时,线程将在下一个取消点上对所有挂起的取消请求进行处理
* `PTHREAD_CANCEL_DISABLE`:对`pthread_cancel`的调用并不会杀死线程。相反,**取消请求对这个线程来说还处于挂起状态**,当取消状态再次变为`PTHREAD_CANCEL_ENABLE`时,线程将在下一个取消点上对所有挂起的取消请求进行处理

如果线程长时间不会调用前面所述函数进入一个取消点,可以通过**下列函数添加取消点**

Expand Down Expand Up @@ -3131,6 +3129,8 @@ pthread_attr_destroy(&attr);
* [屏障](#34-屏障属性)
- 进程共享属性

> **进程共享属性控制着同步对象是否可用于进程与进程之间**
### 3.1 互斥锁属性

**互斥锁属性用`pthread_mutexattr_t`结构表示**
Expand Down Expand Up @@ -3160,8 +3160,8 @@ pthread_attr_destroy(&attr);
<div align="center"> <img src="../pic/apue-threadctr-9.png"/> </div>

* `pshared`
- `PTHREAD_PROCESS_PRIVATE`:默认的行为。进程中的多个线程可以访问用一个同步对象。该值允许pthread线程库提供更有效的互斥锁实现。在多个进程共享多个互斥锁的情况下,pthread线程库可以限制开销较大的互斥锁实现
- `PTHREAD_PROCESS_PRIVATE`:允许相互独立的多个进程把同一个内存数据块映射到它们各自独立的地址空间中。就像多个线程访问共享数据一样,多个进程访问共享数据通常也需要同步。如果设为为该值,那么初始化得到的互斥锁(该锁从多个进程彼此之间共享的内存数据块中分配得到)就能用于这些进程的同步
- `PTHREAD_PROCESS_PRIVATE`:默认的行为。进程中的多个线程可以访问同一个同步对象。该值允许pthread线程库提供更有效的互斥锁实现。在多个进程共享多个互斥锁的情况下,pthread线程库可以限制开销较大的互斥锁实现
- `PTHREAD_PROCESS_SHARED`:允许相互独立的多个进程把同一个内存数据块映射到它们各自独立的地址空间中。就像多个线程访问共享数据一样,多个进程访问共享数据通常也需要同步。如果设为该值,那么初始化得到的互斥锁(该锁从多个进程彼此之间共享的内存数据块中分配得到)就能用于这些进程的同步


### 3)健壮属性的获取和设置
Expand Down Expand Up @@ -3265,12 +3265,12 @@ Single UNIX Specification目前定义了条件变量的2个属性:

线程特定数据也称为线程私有数据,是存储和查询某个线程相关数据的一种机制。它是每个线程私有的数据副本,因此不需要担心与其它线程的同步访问问题

* **无法简单的分配一个每线程数据数组**:因为无法通过线程ID去定位数组中的某个具体数据。因为线程ID并不能保证是小而连续的整数。即使是,我们可能还希望有一些额外包含,防止某个线程的数据与其他线程的数据相混淆(比如线程间的数据可能越界写?)
* **无法简单的分配一个每线程数据数组**:因为无法通过线程ID去定位数组中的某个具体数据。因为线程ID并不能保证是小而连续的整数。即使是,我们可能还希望有一些额外保护,防止某个线程的数据与其他线程的数据相混淆(比如线程间的数据可能越界写?)
* **线程特定数据提供了让基于进程的接口适应多线程环境的机制**。比如errno,线程出现以前,errno定义为进程上下文中全局可访问的整数。为了让线程也能使用那些原本基于进程的系统调用和库例程,errno被重新定义为线程私有数据。这样线程之间不会相互影响

> 一个线程没有办法阻止另一个线程访问它的数据。线程特定数据也不例外。虽然底层的实现部分并不能阻止这种访问能力,但管理线程特定数据的函数可以提高线程间的数据独立性,使得线程不太容易访问到其它线程的线程特定数据
**每个系统支持有限数量的线程特定数据元素,POSIX要求这个限制不小于128(每个进程)****系统****每个进程**维护一个称之为Key结构(一个Key结构就是一个线程特定数据元素)的结构数组,如下图:
**每个系统支持有限数量的线程特定数据元素,POSIX要求这个限制不小于128(每个进程)****系统****每个进程**维护一个称之为Key结构的数组,如下图:

<div align="center"> <img src="../pic/unp-thread-7.png"/> </div>

Expand Down Expand Up @@ -3311,19 +3311,19 @@ pKey数组的所有元素都被初始化为空指针。这128个指针是和进
* 线程调用了`exit``_exit``_Exit``abort`
* 出现其他非正常的退出时

线程退出时,线程特定数据的析构函数将按照操作系统实现中定义的顺序被调用。当所有的析构函数都调用完成之后,系统会检查是否还有非空的线程特定数据值与键关联,如果有的话,再次调用析构函数。这个过程将会一直重复到线程所有的键都为空线程特定数据值,或者已经做了`PTHREAD_DESTRUCTOR_ITERATIONS`中定义的最大次数的尝试
线程退出时,线程特定数据的析构函数将按照操作系统实现中定义的顺序被调用。当所有的析构函数都调用完成之后,系统会检查是否还有非空的线程特定数据值与键关联,如果有的话,再次调用析构函数。这个过程将会一直重复到线程所有的键都为空,或者已经做了`PTHREAD_DESTRUCTOR_ITERATIONS`中定义的最大次数的尝试

**pthread_once函数**

* **onceptr**:onceptr参数指向的变量中的值,确保init参数所指的函数在进程范围内只被调用一次
* **init**:进程范围内,对于一个给定的键,pthread_key_create只能被调用一次。所以可以init可以指向一个pthread_key_create函数,通过onceptr参数确保只调用一次
* **init**:进程范围内,对于一个给定的键,pthread_key_create只能被调用一次。所以init可以指向一个pthread_key_create函数,通过onceptr参数确保只调用一次

### 2)pthread_getspecific和pthread_setspecific函数

<div align="center"> <img src="../pic/unp-thread-10.png"/> </div>

* pthread_getspecific函数在Pthread结构中把对应指定键的指针设置为指向分配的内存
* pthread_setspecific函数返回对应指定键的指针
* pthread_getspecific函数返回对应指定键的指针
* pthread_setspecific函数在Pthread结构中把对应指定键的指针设置为指向分配的内存

### 3)pthread_key_delete函数

Expand Down Expand Up @@ -3371,15 +3371,15 @@ pKey数组的所有元素都被初始化为空指针。这128个指针是和进
* 在返回之前,`sigwait`将从进程中移除那些处于挂起等待状态的信号。如果具体实现支持排队信号,并且信号的多个实例被挂起,那么`sigwait`将会移除该信号的一个实例,其他的实例还要继续排队
* 为了避免错误行为发生,线程在调用`sigwait`前,必须阻塞那些它正在等待的信号。`sigwait`会原子地取消信号集的阻塞状态,直到有新的信号被递送。在返回之前,`sigwait`将恢复线程的信号屏蔽字。如果信号在`sigwait`被调用的时候没有被阻塞,那么在线程完成对`sigwait`的调用之前会出现一个时间窗,在这个时间窗中,信号就可以被发送给线程
* 使用`sigwait`的好处在于它可以简化信号处理,允许把异步产生的信号用同步的方式处理。为了防止信号中断线程,可以把信号加到每个线程的信号屏蔽字中。然后可以安排专用线程处理信号。这些专用线程可以进行函数调用,不需要担心在信号处理程序中调用哪些函数是安全的,因为这些函数调用来自正常的线程上下文,而非会中断线程正常执行的传统信号处理程序
* 如果多个线程在`sigwait`的调用中因等待同一个信号而阻塞,那么在信号递送的时候,就只有一个线程可以从`sigwait`中返回。如果一个信号被捕获,而且一个信号正在`sigwait`调用中等待同一信号,那么这时将由操作系统来决定以何种方式递送信号。操作系统可以让`sigwait`返回,也可以激活信号处理程序,但这两种情况不会同时发生
* 如果多个线程在`sigwait`的调用中因等待同一个信号而阻塞,那么在信号递送的时候,就只有一个线程可以从`sigwait`中返回。如果一个信号被捕获,而且一个线程正在`sigwait`调用中等待同一信号,那么这时将由操作系统来决定以何种方式递送信号。操作系统可以让`sigwait`返回,也可以激活信号处理程序,但这两种情况不会同时发生

要把信号发送给**进程**,可以调用`kill`要把信号发送给**线程**,可以调用`pthread_kill`
**把信号发送给进程**,可以调用`kill`**把信号发送给线程**,可以调用`pthread_kill`

<div align="center"> <img src="../pic/apue-threadctr-29.png"/> </div>

可以传一个`0`值的`signo`来检查线程是否存在。如果信号的默认处理动作是终止该进程,那么把信号传递给某个线程仍然会杀死整个进程

闹钟定时器是进程资源,并且所有的线程共享相同的闹钟。所有,进程中的多个线程不可能互不干扰地使用闹钟定时器
闹钟定时器是进程资源,并且所有的线程共享相同的闹钟。所以,进程中的多个线程不可能互不干扰地使用闹钟定时器

<br>

Expand All @@ -3398,7 +3398,7 @@ pKey数组的所有元素都被初始化为空指针。这128个指针是和进

<div align="center"> <img src="../pic/apue-threadctr-30.png"/> </div>

**该函数可以安装清楚锁的函数,最多3个**
**该函数可以安装清除锁的函数,最多3个**

* `prepare`
- 由父进程在fork创建子进程前调用
Expand Down
6 changes: 3 additions & 3 deletions 计算机网络/UNIX网络编程卷1.md
Original file line number Diff line number Diff line change
Expand Up @@ -1902,14 +1902,14 @@ pthread_key_create函数:
pthread_once函数:

* **onceptr**:onceptr参数指向的变量中的值,确保init参数所指的函数在进程范围内只被调用一次
* **init**:进程范围内,对于一个给定的键,pthread_key_create只能被调用一次。所以可以init可以指向一个pthread_key_create函数,通过onceptr参数确保只调用一次
* **init**:进程范围内,对于一个给定的键,pthread_key_create只能被调用一次。所以init可以指向一个pthread_key_create函数,通过onceptr参数确保只调用一次

### 2)pthread_getspecific和pthread_setspecific函数

<div align="center"> <img src="../pic/unp-thread-10.png"/> </div>

* pthread_getspecific函数在Pthread结构中把对应指定键的指针设置为指向分配的内存
* pthread_setspecific函数返回对应指定键的指针
* pthread_getspecific函数返回对应指定键的指针
* pthread_setspecific函数在Pthread结构中把对应指定键的指针设置为指向分配的内存

## 4.互斥锁

Expand Down

0 comments on commit 423b7c0

Please sign in to comment.