Linux 线程控制

Linux 线程控制

线程属性

同步原语属性

多线程间如何保持数据私有性

基于进程的系统调用如何与线程交互

线程限制

可通过 sysconf 函数查询线程限制。

注意:有些os下使用sysconf无法访问,只是没有提供访问方法,不意味这些限制不存在

线程属性

使用 pthread_attr_t 结构控制线程属性,需要初始化和销毁。

控制初始时是否为detached状态

detachstate可设为两个合法值之一: PTHREAD_CREATE_DETACHED初始化为分离态    PTHREAD_CREATE_JOINABLE正常启动

控制进程栈

对于进程,虚拟地址空间大小固定。因为进程中只有一个栈,所以它大小通常没问题。但对于线程,同样大小虚拟地址空间被所有线程栈共享。如果线程栈累计大小超过可用空间,要减小默认栈大小。stackaddr 时栈最低内存地址,但不一定是栈开始位置,通常栈是从高地址向低地址生长,所以stackaddr是栈结尾位置。

栈大小

gardsize

同步属性

互斥属性

重要的三个属性:

1. 进程共享

进程通过内存映射共享一个变量

PTHREAD_PROCESS_PRIVATE(默认其他进程不能使用这个进程创建的锁)     PTHREAD_PROCESS_SHARED

2. 健壮

 

PTHREAD_MUTEX_STALLED(默认) PTHREAD_MUTEX_ROBUST

持有锁的进程终止时没有释放锁,另一个进程中的线程申请锁。前者等待解锁的进程会被“拖住”;后者不会被“拖住”,而是直接返回 EOWNERDEAD 而不是0

首先,需要了解的是,如果不对该互斥量做状态恢复,那么如果其他进程试图直接对该锁住的互斥量进行解锁的情况下,又有另外的进程试图获取该互斥量,那么试图获取该互斥量的阻塞线程会得到错误码 ENOTRECOVERABLE,发生这种情况会导致该互斥量处于永久不可用状态,此时,我们必须先调用 pthread_mutex_destroy 来 destroy 掉该锁,然后重新用锁的属性和锁的初始化函数来重新初始化该锁。 

为了避免这样的问题,线程可以调用 pthread_mutex_consistent(pthread_mutex_t *mutex) 函数来恢复该锁的一致性,然后调用 pthread_mutex_unlock 对该互斥量解锁,接下来其他进程就可以对该互斥量进行加锁(也就是获取该互斥量)了,这样该互斥量的行为也就恢复正常了。 

3. 类型

 

读写锁属性

 

条件变量属性

包含进程共享属性和时钟属性

时钟属性控制计算 pthread_cond_timedwait 函数的超时参数时使用哪个时钟。在使用 pthread_cond_timedwait 前要用 pthread_condattr_t 对象对条件变量进行初始化。

 

屏蔽属性

只有进程共享属性

线程私有数据

  1. 维护基于每个线程的数据
  2. 提供了让基于进程的接口适应了多线程环境的机制。比如errno

一个进程中所有线程都可以访问这个进程中整个地址空间,除了寄存器无法阻止访问它的数据。线程私有数据也不例外。底层实现不能阻止,但是可提高数据独立性。

在分配前获得一个与数据关联的键,用于获取线程对私有数据的访问。

创建的键存储在keyp指向的内存单元中,这个键可被进程中所有线程使用,每个线程把这个键与不同线程特定数据地址关联。关联的函数为析构函数,线程退出时调用,唯一参数就是该数据地址。

取消选项

pthread_cancel 调用发出取消请求消息。线程在取消请求发出后继续运行,直到线程到某个取消点(即某些POSIX定义的常见函数)。线程启动的默认状态为 PTHREAD_CANCEL_ENABLE,当设为 PTHREAD_CANCEL_DISABLE 时,取消信号不会杀死线程并且取消请求处于挂起状态,当取消状态再变为 PTHREAD_CANCEL_ENABLE 时,线程再下一个取消点处理请求。

可以手动调用专门的取消点函数:

以上为推迟取消,在到达取消点前不会取消。修改为异步取消,线程可以在任意时间撤销。

type 可选:PTHREAD_CANCEL_DEFERRED   PTHREAD_CANCEL_ASYNCHRONOUS

线程和信号

每个线程都有自己的屏蔽字,但信号处理时进程中所有线程共享的。进程中的信号发到单个线程,如果信号与硬件故障相关那么发到引起该事件的线程中,其他信号发送到任意一个线程。

线程中设置屏蔽字

当等候的信号处于挂起状态时sigwait将无阻塞的返回,返回前移除处于挂起状态等待状态的信号。如果支持排队,那么只移除一个。

为避免错误,在调用sigwait前,必须阻塞那些它在等待的信号,sigwait会取消信号集的阻塞状态,直到信号送到。返回前恢复线程屏蔽字。

多个线程在sigwait调用中等待一个信号而阻塞,那么信号到时只有一个线程能返回。

如果一个信号被sigaction注册了处理程序,一个线程调用中等待同一信号,这时由os决定如何,这两种情况不会同时触发。

线程和 fork

调用fork后,子进程只有一个线程,是父进程中调用fork的线程的副本。它继承了地址空间的副本,还从父进程继承了每个互斥量、读写锁、条件变量。但子进程不包含占有锁的进程的副本,所以子进程没法知道占用了哪些锁、要释放哪些锁。如果fork后马上调用exec可以避免这个问题。

线程与 IO

多线程环境下使用pread 和 pwrite,因为进程中所有线程共享相同的文件描述符。

posted @ 2022-08-25 23:01  某某人8265  阅读(108)  评论(0编辑  收藏  举报