多线程编程学习::POSIX 多线程基础(二)
来源:互联网 发布:excel数组 编辑:程序博客网 时间:2024/05/20 20:47
线程建立与使用
创建线程
- 通过
pthread_create()
函数创建线程- 向该函数传递线程函数地址和线程函数参数
- 线程函数只有一个 void* 参数
- 该函数返回 pthread_t 类型的线程ID
- 一般调用该函数创建线程,然后调用
pthread_join()
函数等待线程结束- 在当前线程从函数
pthread_create()
中返回以及新线程被调度执行之间不存在同步关系 - 新线程可能在当前线程从
pthread_create()
返回值前就运行了 - 或在当前线程从
pthread_create()
返回之前,新线程就可能已经运行完毕了
- 在当前线程从函数
pthread_join()
- 阻塞其调用者直到指定线程终止,然后可以选择地保存线程的返回值
- 当
pthread_join()
调用返回时,被连接线程就已经被分离(detached),再也不能连接该线程了 - 如果连接(joining)线程不关心返回值,或者它知道被连接(joined)的线程根本不返回任何值,则可向
pthread_join()
的 &retval 参数传递 NULL,此时,被连接线程的返回值将被忽略
初始线程
- C 程序运行时,首先运行 main() 函数,main() 函数所在线程称为初始线程或主线程
- 初始线程可调用
pthread_self()
获得其 ID,也可调用pthread_exit()
来终止自己 - 从 main() 返回将导致进程终止,也将使进程内所用线程终止
- 在 main() 中调用
pthread_exit()
,这样进程就必须等待所有线程结束后才能终止 - 若初始线程将其 ID 保存在一个其他线程可以访问的空间,则其他线程就可以等待初始线程的终止或者分离初始线程
线程分离
- 分离一个正在运行的线程不会对线程带来任何影响,仅仅是通知系统当该线程结束时,其所属资源可以被回收
- 分离线程意味着通知系统不再需要此线程,允许系统将分配给它的资源回收
- 一个没有被分离的线程终止时会保留其虚拟内存,包括堆栈和其他系统资源
线程生命周期
在任意时刻,线程处于下表的四个基本状态之一。
状态说明就绪 ready线程能够运行,但在等待可用的处理器- 可能刚刚启动
- 或刚刚从阻塞中恢复
- 或被其他线程抢占
- 线程从起始函数中返回
- 或调用pthread_exit
- 或被取消,终止自己并完成所有资源清理工作
线程状态转换如下图。
说明
- 线程开始处于就绪状态
- 当线程运行时,它调用特定的起始函数
- 它可能被其他线程抢占,或者因等待外来事情而阻塞自己
- 最终线程完成工作,或者从起始函数返回,或者调用
pthread_exit
函数,即进入终止状态 - 如果线程已被分离,则它立刻被回收重用;否则,线程停留在终止状态直到被分离或被连接
就绪态
- 线程刚被创建时
- 线程被解除阻塞再次可以运行时
- 运行线程被抢占时,如时间片到
被阻塞
- 试图加锁一个已经被锁住的互斥量
- 等待某个条件变量
- 调用 singwait 等待信号
- 执行无法立即完成的 IO 操作
- 内存页错误之类的系统操作
初始线程(main()函数所在线程)与普通线程区别
- 初始线程的启动函数 main() 是从程序外部调用的;如 crt0.o 文件复制初始化进程并调用 main() 函数;而普通线程的启动函数及其运行参数均由
pthread_create()
函数创建线程时传入,且由 CPU 调度的 - main()函数的参数是 argc 和 argv;普通线程的参数是 void*,且由
pthread_create()
函数传入 - 若普通线程从启动函数中返回,则线程终止,而其他线程依然可以运行;但初始线程从 main() 返回时,进程终止,进程内所有线程也被终止
- 若希望在初始线程终止时,进程中的其他线程继续执行,则需要在初始线程调中调用
pthread_exit()
而非从main()
返回 - 大多数系统,初始线程运行在默认进程堆栈上,该堆栈可以增长到足够尺寸;而某些实现中,普通线程的堆栈空间是受限的
- 如果线程堆栈溢出,则程序会出现段错误
线程睡眠原因
- 被阻塞,需要的某个资源不可用
- 被抢占,即系统将处理器分配给其他线程
pthread_join()
的详细解释
- 用来等待一个线程的结束;
- 是一个线程阻塞函数,调用它的函数将一直等待到被等待的线程结束为止
- 如,主线程调用
pthread_join()
等待它创建的线程运行结束,即主线程调用该函数后会被阻塞 - 当函数返回时,被等待的线程的资源被回收
- 若此时新线程没有运行,则它将在主线程被阻塞后从就绪态进入运行态;当新线程运行完毕并返回时,主线程才会被解除阻塞,返回就绪态;当处理器可用时,主线程或立即执行或等到创建的线程终止后重新运行直到结束
线程终止
- 一般地,线程从启动函数返回来终止自己
- 当调用
pthread_exit()
退出线程或者调用pthread_cancel()
取消线程时,线程在调用每个清理过程后也进入终止状态 - 清理过程又线程通过
pthread_cleanup_push()
注册,且尚未通过pthread_cleanup_poo()
删除
Linux 系统僵尸线程
- 如果线程已经被分离,则会被回收;否则,线程处于终止状态,仍然可以被其他线程调用
pthread_join()
连接 - 这种线程被称为僵尸线程,像 Uni 系统中的进程已经结束但还没有被一个
wait/waitpid
调用回收一样,即使已经死了但还存在 - 僵尸线程可能会保留其运行时的大部分甚至所有资源,因此不应该让线程长时间处于这种状态;当创建不需要连接的线程时,应该使用 detachstate 属性建立线程使其自动分离
线程回收
- 如果使用 detachstate 属性(即设置属性为 PTHREAD_CREATE_DETACH )建立线程,或者调用
pthread_detach()
分离线程,则当线程结束时将被立刻回收 - 如果终止线程没有被分离,则它将一直处于终止状态直到被分离(通过
pthread_detach
)或者被连接(通过pthread_join
) - 线程一旦被分离,就不能再访问它
- 回收将释放所有在线程终止时未释放的系统和进程资源,包括
- 保存线程返回值的内存空间、堆栈
- 保存寄存器状态的内存空间
- 实际上线程终止时上述资源就不能被访问了
- 一旦线程被回收,线程ID就无效了,不能再连接、取消或者执行其他任何操作
- 终止线程ID可能被分给新线程
阅读全文
0 0
- 多线程编程学习::POSIX 多线程基础(二)
- Posix多线程编程学习笔记(二)
- 多线程编程学习::POSIX 多线程基础(一)
- 多线程编程学习::POSIX 多线程基础(三)
- POSIX多线程编程(二)
- Posix多线程编程学习笔记(一)—线程基础
- poSix多线程笔记二-----基础
- POSIX多线程编程(二)--pthread_join
- 《posix多线程编程》笔记(二)
- Posix多线程编程学习笔记(一)
- Posix多线程编程学习笔记(一)
- Posix多线程编程学习笔记
- Posix多线程编程学习笔记
- Posix多线程编程学习笔记
- Posix多线程编程学习笔记
- Posix多线程编程学习笔记
- Posix多线程编程学习笔记
- POSIX多线程编程(一)
- 类加载器
- java中AWT和SWing的区别与联系
- [学习笔记][Java编程思想]第10章:内部类
- C数组解决魔术师发牌问题
- 【Ubuntu】安装字体
- 多线程编程学习::POSIX 多线程基础(二)
- SpringBoot学习(一)
- Mysql之查询
- Torch中多GPU运行代码学习
- Java手动实现简单 ArrayList
- (五)PipedInputStream与PipedOutputStream
- Hibernate
- 免费领取微软OneDrive网盘5T容量,非扩容!
- hdu4812 D Tree