《Unix高级环境编编程》 第十二章 Thread Control

本章学习如何控制线程行为的细节
本章涉及thread attributes(线程属性)、synchronization primitive attributes(同步原语属性)以及线程如何使得数据在相同process中保持私有。

二、Thread Limits

1. 如何查询thread limits?这些限制的所用是什么?

使用sysconf能够查询到线程的限制信息。
使用这些limits能够帮助提升应用程序在不同操作系统实现上的移植性(portability)

2. process创建的关键字(key)是什么?

线程由于共享进程的地址空间,因此global variable是共享的,而key用于每个线程享有一些私有数据。

三、Thread Attribute

3. 如何设置thread的属性?如何初始化?

pthread_attr_t结构体用于修改属性
pthread_attr_init/destory 用于初始化/销毁 属性

4. init/destory属性的注意点

  • 如果init是使用动态分配的空间,destory会释放该空间
  • 我们不需要检查destory的返回值,因为只要初始化成功,destory就不会失败

5. pthread_attr_t is opaque to applications(对应用程序难以理解)

app不知道其内部结构能够提升app的可移植性

6. pthread_detach允许操作系统在thread exit时,回收资源(reclaim resource)

7. thread属性有几个?是哪些?

四个
figure 12.2

8. pthread_attr_setdetachstate能设置detachstate线程属性

为两种值之一: PTHREAD_CREATE_DETACHED or PTHREAD_CREATE_JOINABLE

9. 支持stack属性是POSIX的可选项

编译器间可以使用 _POSIX_THREAD_ATTR_STACKADDR或者 _POSIX_THREAD_ATTR_STACKSIZE检测是否支持

运行期间用sysconf参数 _SC_THREAD_ATTR_STACKADDR or _SC_THREAD_ATTR_STACKSIZE检测

10. stack attr如何设置?

使用 pthread_attr_getstack/setstack设置
链接:

在用光(run out of)thread stacks的虚拟地址空间时,使用malloc or mmap分配空间,然后用setstack设置。

11. stack attr的两个注意点

  • 对进程,虚拟地址空间的数量是固定的,只有一个stack,stack的size不是问题
  • 对于线程,线程需要共享同样数量的虚拟地址空间

12. 单独设置stack size

pthread_attr_getstacksize/setstacksize

在你想要修改stack size却不想分配thread stacks时很有用

13. guardsize attribute有什么用?如何设置

在stack空间之后有一块内存用于保护stack overflow的问题。这块内存的大小就是guardsize,默认被设置为PAGESIZE bytes。如果stack pointer溢出到guard buffer中,会产生错误,通常是signal

  • guardsize = 0表示关闭该特性(feature)
  • 如果我们改变stackaddr属性,意味着系统假设我们将要管理 stacks并且关闭guard buffers

guardsize使用pthread_attr_getguardsize/setguardsize来设置

14. concurrency level属性的作用?设置方法和注意点

作用

控制用户层threads映射到kernel threads or processes的数量

设置

pthread_getconcurrency/setconcurrency

注意点

  • getconcurrency返回当前concurrency level
  • 如果操作系统控制concurrency level, getconcurrency会返回0
  • 可以向set传入 level 0,则让系统自己决定。这种用法还能清除上次调用的影响。

四、Syschronization Attributes(同步属性)

15. mutex属性初始化和销毁

pthread_mutexattr_init/destory
使用pthread_mutexattr_t结构体,其中process-shared属性和type属性很有用。

16. 存在一种机制允许独立的进程将内存的同一区域映射到它们独立的地址空间

17. 获取和设置process-shared attribute

pthread_mutexattr_getpshared/setpshared
该属性被设置为PTHREAD_PROCESS_PRIVATE能使得多线程访问同样的synchronization object(同步实体)

18. type属性有哪些?如何设置和注意点

Mutex type behavior

各个属性作用如下

属性作用
PTHREAD_MUTEX_NORMALdon’t do any special error checking or deadlock detection.
PTHREAD_MUTEX_ERRORCHECKprovides error checking.
PTHREAD_MUTEX_RECURSIVEallows the same thread to lock it multiple times without first unlocking it. A recursive mutex maintains a lock count and isn’t released until it is unlocked the same number of times it is locked. Thus, if you lock a recursive mutex twice and then unlock it, the mutex remains locked until it is unlocked a second time.
PTHREAD_MUTEX_DEFAULTLinux 3.2.0 maps this type to the normal mutex type

设置方式

pthread_mutexattr_gettype/gettype

19. recursive mutex使用注意点

  • 如果recursive mutex被lock多次,并且在pthread_cond_wait中,condition(条件)将永远不能被满足,因为pthread_cond_wait的unlock不能释放mutex
  • 只有在其他方法都不行时,才考虑使用recursive locks
  • 12.4的example(p397)有使用recursive和不使用的例程讲解

20 sleep和nanosleep用于计时

21 读写锁属性的相关设置

与mutex类似,使用pthread_rwlockaddr_t结构体
pthread_rwlockattr_init / destory
pthread_rwlockattr_getpshared / setpshared

22 条件变量属性的相关设置

使用pthread_condattr_t结构体
pthread_condattr_init/destory

也支持process-shared attribute

pthread_condattr_getpshared / setpshared

五、Reentrancy

除了如下图的functions,定义在Single UNIX Specification中的functions都确保thread-safe
12.9

  • unistd.h中_POSIX_THREAD_SAFE_FUNCTIONS决定是否支持thread-safe, 或者在sysconf中使用_SC_THREAD_SAFE_FUNCTIONS

  • 下图是POSIX.1中非线程安全functions的替换版本
    12.10

23 POSIX.1提供以thread-safe的方法操作FILE object

  • 使用flockfileorftrylockfile获取FILE object相关联的锁
  • 该锁是 recursive(可迭代的):在你已经获得它的时候再次请求它,但是不会出现死锁(deadlocking)
  • 尽管lock的实际实现没有特定,它也需要所有标准IO routines(程序)操作FILE object如同内部调用flockfile/funlockfile

24 标准IO需要他们各自的lock,而以字符为单位I/O性能会下降很多,因此有unlock版本的标准IO

getchar_unlock/getc_unlock
puchar_unlock/putc_unlock

这四个函数只有在flockfile/ftrylockfilefunlockfile环绕时才被调用。否则会产生无法预料的结果(由于对数据的不同步访问)。

25 如何自定义reentrant函数?

  1. 首先各个线程使用各自的buffer
  2. 使用mutex来保证线程安全

我们可以使用读写锁来允许同时对数据的访问,但是该数据的并发调用不是很频繁,这样提升不了多少性能

26 我们使得函数线程安全并不代表对于signal handlers也是reentrant的

如果此时2个线程运行该函数,线程a已经获得mutex,此时产生信号打断该线程。那么线程b由于获得不了mutex会一直阻塞。

因此我们必须使用recursive mutex来防止其他线程在我们查看数据结构时改变数据,也能防止signal handlers产生的deadlock

六、Thread-Specific Data

27 线程私有数据的作用?

例如errno,很多地方都会调用。errno就是用thread-private date 实现。这样一线程中改变errno不会影响其他thread中errno的值。

28 进程中key是什么?如何创建?注意点?

线程由于共享进程的地址空间,因此全局数据共享,key用于每个线程共享一些私有数据。在使用thread-private data前需要先创建key

创建key:pthread_key_create- thread-specific data key creation

#include <pthread.h>

int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));

所有线程都可以使用同一个key,但是不同多线程会将不同的thread-private data地址与key联系起来。

  • thread正常中止时如调用pthread_exit or return,destructor会被执行。
  • thread通过exit,_exit,_Exit, abort或者其他异常终止时,destructor不会被调用
  • destructor可以用来释放给thread-specific data分配的空间

29 进程可创建key的上限是:PTHREAD_KEYS_MAX

30 process会确保keys相关的thread-specific数据为null

会检测最多:PTHREAD_DESTRUCTOR_ITERATIONS

31 如何删除key?

pthread_key_delete

  • 调用该函数不会调用destructor。会释放与key相关的thread-specific data的所有内存。

32 pthread_once是什么?

thread确保初始化程序只运行一次

pthread_once - dynamic package initialization

#include <pthread.h>

int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
pthread_once_t once_control = PTHREAD_ONCE_INIT;
        //Returns:0 if OK, error number on failure

once_control必须是非局部变量,为global或者static变量并且初始化为PTHREAD_ONCE_INIT

33 如何绑定thread-private data?注意点?

获得和设置绑定在key上的数据

#include <pthread.h>

void *pthread_getspecific(pthread_key_t key);
        //Returns:thread-specific data value or NULL if no value has been associated with the key
int pthread_setspecific(pthread_key_t key, const void *value);
        //Returns:0 if OK, error number on failure

注意点

  1. 我们使用

34

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值