APUE读书笔记(20) 线程控制(下)

一:线程特定数据:
  线程特定数据也称为线程私有数据,是存储和查询某个特定线程相关数据的一种机制。线程模型是可以共享进程中的一些数据,但是为什么又需要有线程特定数据呢?这主要基于两点:
  第一:有时候需要维护基于每线程的数据。虽然线程id是一个整数且唯一,但是基于线程id作为数组的索引会有不够安全(不太清楚这里的不安全指的是什么)。作者提到:我们希望可能有一些额外的保护,防止某个线程的数据与其他线程的数据相混淆。
  第二:提供基于进程的接口适应多线程环境的机制。比如errno,errno是一个进程内可访问的全局变量。系统调用或者库例程失败的时候会设置errno。为了让线程也可以使用errno,errno被定义为线程私有数据,这样一旦一个线程改变了errno,也不会影响其他线程。
  再分配线程特定数据之前,需要创建于该数据相关联的键。
在这里插入图片描述
  除了能够创建键,还可以传入一个析构函数地址,这样在该线程被销毁之前,系统会调用该线程的析构函数。但是只有在线程正常退出的时候,该析构函数才会被调用,如果是非正常退出,则不会。一般来说,线程通过malloc为其分配线程特定数据,而析构函数则是free该内存。如果线程非正常退出,则这一块内存没有被free,那么就会出现线程级别的内存泄漏。
  对于所有的线程,还可以使用函数来取消线程与键的特定关联
在这里插入图片描述
  值得注意的是,调用delete函数不会调用线程的析构函数。
二:取消选项
  有两个线程属性没有包含在pthread_attr_t结构中,他们是可取消状态和可取消类型。这两个属性影响线程在相应ptherd_cancel函数调用所呈现的行为。
  可取消状态可以是enable和disable,可以调用以下函数来改变他的状态。
在这里插入图片描述
  取消并不等于线程终止,线程会在到达某个取消点之后终止,这些取消点包括以下函数
APUE读书笔记(20) 线程控制(下)_第1张图片
  线程启动的时候,可取消状态默认是enable,如果改为了disable之后,执行取消不会杀死线程,只有当可取消状态设置为了enable之后并且到达了下一个取消点才会杀死线程。
三:线程和信号
  每个线程都会有自己的信号屏蔽字,但是信号的处理是进程中所有线程所共享的。这意味着单个线程可以阻止某些信号。而且进程内的某一个线程修改了对信号的处理行为,那么其他线程必须共享这个改变。如果一个线程选择忽略某个信号,其他线程可以通过两种方式取消线程的信号选择:恢复信号的默认处理行为,或者为信号设置一个信号的信号处理行为。
  进程的信号是递送给某个线程的,如果一个信号与机器故障有关,那么这个信号会被递送给相应的线程,其他信号则会随机递送。线程调用下面的函数来取消信号发送
APUE读书笔记(20) 线程控制(下)_第2张图片
  线程也可以调用sigwait去等到一个或者多个信号的出现在这里插入图片描述
  set指定了线程等待的信号集。
四:线程和fork
  当线程调用fork的时候,就为子进程创建了整个进程的地址空间的副本。子进程虽然与父进程是完全不同的两个进程,但是只要这两个进程没有对内存内容进行改动,则他们还可以共享内存页的副本。
  在子进程内部只存在一个线程,就是调用fork的那个线程。如果父进程的线程占有锁,那么子进程的线程同样也占有锁,但是他并没有占有锁的线程的副本,所有子进程并不知道占有了那些锁,需要释放那些锁。所以在多线程的进程中,为了避免出现不一致的情况,在fork之后的子进程调用一个exec函数之前,他只能使用异步安全的函数(这也是为了避免调用异步不安全的函数出现数据不一致问题)要清除锁的状态,可以调用下面的函数
在这里插入图片描述
五:线程和IO
  进程的多线程同时共享文件描述符,但是如果两个线程都调用了lseek(设置文件偏移量)然后调用read,那么两个线程其实会读取同一条数据,本质上就是同时修改一份数据了。那么为了解决这个问题,可以使用原子操作pread,使设置文件偏移量和读取文件内容变为一个原子操作。

你可能感兴趣的:(APUE)