线程剖析(part2)—线程控制及线程属性

zz/2024/2/25 22:27:08

前言


在博主的上一篇博客中讲述了线程的基本概念及线程创建,没有看过的小伙伴可以点击这里:

linux线程剖析(part1)—1个“假”的tcb

本篇博文将重点从两个方面:线程控制(线程等待、线程终止)及线程属性来进一步分析线程特点。


线程终止


首先,我们需要知道线程终止的几种方式:

1.从线程函数中return(特殊:从main函数中return,代表进程退出,也代表主线程退出。那么此时线程必定被终止。)
2.直接调用pthread_exit函数终止线程(注意:在线程内调用exit终止的是进程而非线程)
3.调用pthread_cancel函数来取消线程,从而终止线程。

与线程终止有关的函数:

2

下面我们来编写代码实现线程终止。

用pthread_exit函数终止线程
1
运行结果:
3
用命令查看,该进程是单进程。

用pthread_cancel函数取消线程

从主线程中取消新线程:
5
执行结果:
6

线程自己取消自己:
7
执行结果:
8


线程等待


对于线程等待,我们需要知道以下几点:

1.线程一旦出错,必须由进程承担后果。对于线程,我们只关心它的两种运行情况:
代码跑完了,结果正确
代码跑完了,结果不正确
如果代码都没跑完,中途退出。这意味着进程也会退出,所以就无法查看其退出原因。
2.线程出错,导致进程退出。则属于该进程的其他线程也会退出,因为线程的资源由进程分配。所以一般多进程比多线程的程序稳定。

因为多线程程序的不稳定性, 如果一个线程结束运行但没有被join,则它的状态类似于进程中的僵尸进程, 即还有一部分资源没有被回收,导致内存泄漏。
所以创建线程者应该调⽤pthread_join来等待线程运行结束,并可得到线程的退出码来回收其资源。   

线程等待函数:pthread_join
表达式:
1

调⽤用该函数的线程将挂起等待,直到id为thread的线程终止。

若thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:

  1. 如果thread线程通过return返回retval所指向的单元⾥里存放的是thread线程函数的返回值。
  2. 如果thread线程被别的线程调用pthread_cancel异常终止掉,retval所指向的单元⾥里存放的是常数PTHREAD_CANCELED。
  3. 如果thread线程自己调用pthread_exit终止,retval所指向的单元存放的是传给 pthread_exit的参数。 如果对thread线程的终止状态不感兴趣,可以传NULL给retval参数。

下面我们来编写程序实现进程等待。

为了对比方便,将上述retval返回值的所有可能情况汇总在一起:
9

10

得到如下结果:
12

至此,线程控制结束。


线程属性


总的来说,在任何一个时间点上。线程有两种属性:

1.可结合(joinable)属性:线程的默认属性。能够被其他线程收回其资源和杀死,在被其他线程回收之前,它的存储器资源 (例如栈)是不释放的。
2.分离(detached)属性:不能被其他线程回收或杀死,它的存储器资源在它终止时由系统⾃自动释放。

注:为了避免存储器泄漏,每个可结合线程都应该要么被显示地回收,即调用pthread_join;要么通过调用pthread_detach函数被分离。

线程分离函数pthread_detach
13

下面通过代码实现线程分离:

20

21

因为线程分离后就不能再被等待,所以在程序中加入等待函数,如果线程分离成功,就会打印出错信息。

运行结果如下:
22

等待函数打印出错信息,线程分离成功


The End 


由于调用pthread_join后,如果该线程没有运行结束,调用者会被阻塞,在有些情况下我们并不希望如此。

例如,在Web服务器中当主线程为每个新来的连接请求创建⼀个子线程进行处理的时候,主线程并不希望因为调用pthread_join⽽而阻塞(因为还要继续处理之后到来的连接请求)。这时可以在子线程中加入代码     pthread_detach(pthread_self()) 或者主线程调用pthread_detach(thread_id)(非阻塞,可立即返回) 。

将子线程的状态设置为分离的(detached),如此一来,该线程运行结束后会自动释放所有资源。


http://www.ngui.cc/zz/2689570.html

相关文章

shell脚本初探——概念篇

ForeWord 本文介绍了shell脚本的一些基础知识。 Key Point: Shell概念及发展历史shell执行脚本shell变量Shell特殊字符使用( $() [] [[]]等) tips:全文阅读需8minPart1:Concept&History 1. Concept 1.Shell概念 我们知道&#xff…

输出1到5的阶乘值(静态变量)

#include <stdio.h> #include <conio.h> int main(){ int fac(int n); int i; for(i1;i<5;i) printf("%d!%d\n",i,fac(i)); getch(); return 0; } int fac(int n){ static int f1; ff*n; return f; }

图-笔记

1.若E是有向边&#xff08;也称为弧&#xff09;的有限集合时&#xff0c;则图G为有向图&#xff1b;若E是无向边&#xff08;简称边&#xff09;的有限集合时&#xff0c;则图G为无向图。 2.有n(n-1)/2条边的无向图称为完全图&#xff0c;具有n(n-1)条弧的有向图称为有向完全…

《计算机网络》-数据链路层笔记及部分课后习题

第三章 3-1.数据链路(即逻辑链路)与链路(即物理链路)有何区别? “电路接通了”与”数据链路接通了”的区别何在? 答&#xff1a;数据链路与链路的区别在于数据链路出链路外&#xff0c;还必须有一些必要的规程来控制数据的传输&#xff0c;因此&#xff0c;数据链路比链路多…

c#数字华容道

代码如下&#xff1a; using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;namespace WindowsFormsApp6{ …