程序员的自我修养 8.8分
读书笔记 运行库 线程的访问权限
超级露

线程的访问权限

线程的访问能力非常自由,它可以访问进程内存里的所有数据,甚至包括其他线程的堆栈(如果它知道其他线程的堆栈地址,然而这是很少见的情况),但实际运用中线程也拥有自己的私有存储空间,包括:

1. 栈(尽管并非完全无法被其他线程访问,但一般情况下仍然可以认为是私有的数据)。

2. 线程局部存储(Thread Local Storage,TLS),线程局部存储是某些操作系统为线程单独提供的私有空间,但通常只具有很有限的尺寸。

3. 寄存器(包括PC寄存器),寄存器是执行流的基本数据,因此为线程私有。

线程之间共享(进程所有):

1. 全局变量

2. 堆上的数据

3. 函数里的静态变量

4. 程序代码,任何线程都有权利读取并执行任何代码

5. 打开文件,A线程打开的文件可以由B线程读写

C/C++运行库在多线程环境遇到的问题

1. errno:在C标准库里,大多数错误代码是在函数返回之前赋值在名为errno的全局变量里的。多线程并发的时候,有可能A线程的errno的值在获取之前被B线程给覆盖掉,从而获得错误的出错信息。

2. strtok()等函数都会使用函数内部的局部静态变量来存储字符串的位置,不同的线程调用这个函数将会把它内部的局部静态变量弄混乱。

3. malloc/new与free/delete:堆分配/释放函数或关键字在不加锁的情况下是线程不安全的。由于这些函数或关键字的调用十分频繁,因此在保证线程安全的时候显得十分繁琐。

4. 异常处理:在早期的C++运行库里,不同的线程抛出异常会彼此冲突,从而造成信息丢失的情况。

5. printf/fprintf及其它IO函数:流输出函数同样是线程不安全的,因为它们共享了同一个控制台或文件输出。不同的输出文件时,信息会混杂在一起。

6. 其它线程不安全函数:包括与信号相关的一些函数。

通常情况下,C标准库在不进行线程安全保护的情况下自然地具有线程安全的属性的函数有(不考虑errno的因素):

1. 字符处理(ctype.h),包括isdigit、toupper等,这些函数同时还是可重入的。

2. 字符串处理函数(string.h),包括strlen、strcmp等,但其中涉及对参数中的数组进行写入的函数(如strcpy)仅在参数中的数组各不相同时可以并发。

3. 数学函数(math.h),包括sin、pow等,这些函数同时还是可重入的。

4. 字符串转整数/浮点数(stdlib.h),包括atof、atoi、atol、strtod、strtol、strtoul。

5. 获取环境变量(stdlib.h),包括getenv,这个函数同时还是可重入的。

6. 变长数组辅助函数(stdarg.h)

7. 非局部跳转函数(setjmp.h),包括setjmp和longjmp,前提是longjmp仅跳转到本线程设置的jmpbuf上。

为了解决C标准库在多线程环境下的窘迫处境,许多编译器附带了多线程版本的运行库。在MSVC中,可用/MT或/MTd等参数指定使用多线程运行库。

0
《程序员的自我修养》的全部笔记 280篇
豆瓣
我们的精神角落
免费下载 iOS / Android 版客户端