线程的一些重要知识:
线程共享的资源
- 进程内存空间:所有线程共享相同的地址空间,包括代码段、数据段和堆。
- 打开的文件描述符:线程可以访问进程打开的文件和I/O设备。
- 全局变量:共享进程的全局变量和静态变量。
- 信号处理器:线程共享进程的信号处理机制。
线程独有的资源
- 线程ID:每个线程都有一个唯一的线程标识符(Thread ID)。
- 寄存器集:每个线程有独立的寄存器集,包括程序计数器(PC)和栈指针(SP)。
- 栈:每个线程有自己的栈空间,用于函数调用、局部变量和返回地址。
- 优先级和调度信息:每个线程有自己的优先级和调度信息,由操作系统调度器管理。
- 信号掩码:线程可以有自己的信号屏蔽字,控制哪些信号可以被处理。
线程的创建和栈的管理
独立栈:当创建一个新线程时,操作系统会为这个线程分配一个全新的、独立的栈。新线程的栈从头开始,并不包含原有线程的调用栈。
起始函数:新线程从指定的起始函数开始执行,因此它的栈一开始只包含这个起始函数的栈帧,而不包括原线程的栈帧
关于这些线程私有资源共有资源的其实不应该类比进程来对比记忆。反而应该拿出刚开始学习C语言时,关于函数局部变量、静态局部变量、全部变量这些来帮助理解。你会发现完全就是一样的。当然最核心本质的把它理解透还是对于栈、静态存储空间、堆空间这些的理解。更本质一些就是说整个虚拟地址空间和内存的组织了。
12.3 线程并发
函数:
pthread_creat
pthread_self : 获得自己的TID
pthread_exit : 终止线程,如果主线程调用这个会等到其他线程也终止之后才终止进程。如 果某个线程使用exit,那么整个进程包含所有正在运行的线程在内都会终止。
pthread_cancle : 可以用tid作为参数终止指定的线程。
pthread_join : 等待其他线程终止,需要指定等待的线程,不能想wait一样等待任意的。
pthread_detach : 一般情况下我们用join显示等待回收子线程。但还有很多情况其实子线程 和主线程是相互独立的,因此不需要显示等待子线程运行结束,这时候用detach说明 是分离的,使用detache之后子线程运行结束会自动回收。其实detach用的也很多,只是示例喜欢用join
pthread_once : 只用一次,就跟静态全局变量一样,只有第一次会调用,其他时候不会调用
12.5 信号量
sem_init
sem_wait //P
sem_post //V
可以把sem_wait包装成P,把sem_post包装成V
12.6用线程提高并行性
12.7 其他并发问题
12.7.1 线程安全
四个(不相交的)线程不安全函数类:
- 不保护共享变量的函数
- 保持跨越多个调用的状态的函数
- 返回指向静态变量的指针的函数
- 调用线程不安全函数的函数
简单地说就是:使用了公共变量、依赖于公共变量、返回公共变量的函数
12.7.2 可重入性
可重入函数是线程安全函数的真子集
线程安全函数:可以在多线程环境中安全地被多个线程同时调用,通常通过内部同步机制来确保线程安全性。标准库函数中许多是线程安全的,但这取决于具体实现。
可重入函数:即使在被中断和重新进入的情况下,也能保持正确性,通常不依赖于全局或静态变量。它们可以被中断并从中断点继续执行而不产生错误