Linux —— 线程

news2025/1/13 3:18:34

一,线程概念

        在一程序内,一个执行路线称为线程thread,即线程是一个进程内部的控制序列;

  • 一切进程至少都有一个执行线程;
  • 线程在进程内部运行,本质是在进程地址空间内运行;
  • 在Linux系统中,CPU看到的PCB都要比传统的进程更加轻量化;
  • 透过进程虚拟地址空间,可看到进程的大部分资源;将进程资源合理分配给每个执行流,就形成线程执行流;

线程优点

  • 创建新线程的代价要比创建新进程小的多;
  • 与进程间的切换相比,线程间的切换需要操作系统所做的工作要少很多;
  • 线程占用资源比进程少很多;
  • 能充分利用多处理器的可并行数量;
  • 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务;
  • 计算密集型应用,为了提高性能,将I/O操作重叠;线程可同时等待不同的I/O操作;

线程缺点

  • 性能损失,一个很少被外部事件阻塞的计算密集型线程往往无法与其他线程共享一个处理器;如计算密集型线程的数量比可用的处理器多,可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变;
  • 健壮性降低,编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话即线程间缺乏保护;
  • 缺乏访问控制,进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响;
  • 编程难度提高,编写与调试一个多线程程序比单线程困难的多;

线程异常

  • 单个线程如出现除零,野指针等问题导致线程崩溃,进程也会随之崩溃;
  • 线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程;进程终止,该进程内的所有线程也会退出;

线程用途

  • 合理的使用多线程,能提高CPU密集型程序的执行效率;
  • 合理的使用多线程,能提高I/O密集型程序的用户体验;

二,Linux进程与线程

  • 进程是资源分配的基本单位;
  • 线程是调度的基本单位;
  • 线程共享进程数据,但也拥有自己的一部分数据;
    • 线程ID;
    • 一组寄存器;
    • 栈;
    • errno;
    • 信号屏蔽字;
    • 调度优先级;

        进程的多个线程共享同一地址空间,因此Text Segment、Data Segment都是共享的;如定义一个函数,在各个线程中都可调用,如定义一个全局变量,在各线程都可访问到,除此之外,各线程还共享以下进程资源和环境:

  • 文件描述符;
  • 每种信号的处理方式(SIG_IGN、SIG_DFL或自定义信号处理函数);
  • 当前工作目录;
  • 用户id和组id;

三,Linux线程控制

POSIX线程库

  • 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以”pthread_“开头的;
  • 要使用这些函数库,引用头文件<pthread.h>;
  • 链接这些线程函数库,使用编译器命令”-lpthread“选项;

创建线程

//创建新线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(*start_routine)(void*), void *arg);
  • thread,返回线程的ID;
  • attr,设置线程的属性,如为NULL表示使用默认属性;
  • start_routine,函数地址,线程启动后执行的函数;
  • arg,传给线程启动函数的参数;

返回值

  • 成功返回0,失败返回错误码;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>

void* rout(void* arg){
    for( ; ; ){
        printf("I am thread1\n");
        sleep(1);
    }
}

int main(){
    pthread_t tid;
    int ret = pthread_create(&tid, NULL, rout, NULL);
    if(ret != 0){
        fprintf(stderr, "pthread_create: %s\n", strerror(ret));
        exit(EXIT_FAILURE);
    }
    for( ; ; ){
        printf("I am main thread\n");
        sleep(1);
    }
}
[wz@192 Desktop]$ gcc -o test test.c -lpthread
[wz@192 Desktop]$ ldd test
	linux-vdso.so.1 =>  (0x00007ffce0bb2000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f9ab6dd8000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f9ab6a0a000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f9ab6ff4000)
[wz@192 Desktop]$ ./test
I am main thread
I am thread1
I am main thread
I am thread1
I am main thread
I am thread1

线程ID及进程地址空间布局

  • pthread_create函数会产生一个线程ID,存放在第一参数所指向的地址;此线程ID与前面所说的线程ID不是一回事;此前所说的线程ID属于进程调度范畴,因线程是轻量级进程,是OS调度的最小单位,所以需一个数值来唯一标识该线程;
  • pthread_create函数第一个参数指向一个虚拟内存单元,该内存单元地址即为新创建线程的线程ID,属于NPTL线程库范畴;线程库的后续操作,就是根据该线程ID来操作线程的;
  • 线程库NPTL提供了pthread_self函数,可获得线程自身ID;

        pthread_t类型是什么,取决于实现;对于Linux目前实现的NPTL,pthread_t类型的线程ID,本质上是一个进程地址空间的一个地址;

线程终止

如需终止某个线程而不是整个进程,有三种方法:

  • 从线程函数return,此方法对主线程不适用,从main函数return相当于调用exit;
  • 线程可调用pthread_exit终止自己;
  • 线程可调用pthread_cancel终止同一进程中的另一个线程;
void pthread_exit(void* value_ptr);
  • vaule_ptr,不要指向一个局部变量;
  • pthread_exit或return返回的指针指向的内存单元必须是全局或是用malloc分配的,不能在线程函数的栈上分配,因为当其他线程得到这个返回指针时线程函数已经退出;
int pthread_cancel(pthread_t thread);
  • 成功返回0,失败返回错误码;

线程等待

为何需要线程等待:

  • 已退出的线程,其空间没有被释放,仍然在进程的地址空间内;
  • 创建新的线程不会复用刚才退出线程的地址空间;
int pthread_join(pthread_t thread, void** value_ptr);
  • value_ptr,指向一个指针,然后在指向线程的返回值;
  • 成功返回0,失败返回错误码;

        调用该函数的线程将挂起等待,直到id为thread的线程终止;thread的线程以不同的方法终止,通过pthread_join得到的终止状态也是不同的:

  • 如thread线程通过return返回,value_ptr所指向的单元存放的时thread线程函数的返回值;
  • 如thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数;
  • 如thread线程被别的线程调用pthread_cancel异常终止的,value_ptr所指向的单元存放的是常数PTHREAD_CANCELED;
  • 如对thread线程的终止状态不感兴趣,可对value_ptr传NULL;

#include <stdio.h>    
#include <stdlib.h>  
#include <unistd.h> 
#include <pthread.h> 

void* thread1(void* arg){
    printf("thread1 returning ...\n");
    int *p = (int*)malloc(sizeof(int));
    *p = 1;
    return (void*)p;
}

void* thread2(void* arg){
    printf("thread1 exiting ...\n");
    int *p = (int*)malloc(sizeof(int));
    *p = 2;
    pthread_exit((void*)p);
}

void* thread3(void* arg){
    while(1){
        printf("thread3 running ...\n");
        sleep(1);
    } 
    return NULL;
}

int main(){
    pthread_t tid;
    void* ret;
    //线程1,return
    pthread_create(&tid, NULL, thread1, NULL);
    pthread_join(tid, &ret);
    printf("thread1 return, thread id %x, return code: %d\n", tid, *(int*)ret);
    free(ret);
    //线程2,exit
    pthread_create(&tid, NULL, thread2, NULL);
    pthread_join(tid, &ret);
    printf("thread2 return, thread id %x, return code: %d\n", tid, *(int*)ret);
    free(ret);
    //线程3,cancel by other
    pthread_create(&tid, NULL, thread3, NULL);
    sleep(3);
    pthread_cancel(tid);
    pthread_join(tid, &ret);
    if(ret == PTHREAD_CANCELED)
        printf("thread3 return, thread id %x, return code: PTHREAD_CANCELED\n", tid);
    else
        printf("thread3 return, thread id %x, return code: NULL\n", tid);
}
[wz@192 Desktop]$ gcc -o test test.c -lpthread
[wz@192 Desktop]$ ./test 
thread1 returning ...
thread1 return, thread id 2d3f6700, return code: 1
thread1 exiting ...
thread2 return, thread id 2d3f6700, return code: 2
thread3 running ...
thread3 running ...
thread3 running ...
thread3 return, thread id 2d3f6700, return code: PTHREAD_CANCELED

线程分离

  • 默认情况下,新创建的线程是joinable的,线程退出后,需要对其进行pthread_join操作,否则无法释放资源,从而造成系统泄露;
  • 如不关心线程的返回值,join是一种负担,此时可告诉系统,当线程退出时,自动释放线程资源;
  • joinable与detach是冲突的,线程不可既是joinable又是detach;
int pthread_detach(pthread_t thread);
//可是线程组内其他线程对目标线程进行分离,也可是线程自己分离
pthread_detach(pthread_self());
#include <stdio.h>    
#include <stdlib.h>  
#include <unistd.h> 
#include <pthread.h> 

void* thread_run(void* arg){
    pthread_detach(pthread_self());
    printf("%s\n", (char*)arg);
    return NULL;
}

int main(){
    pthread_t tid;
    if(pthread_create(&tid, NULL, thread_run, "thread run ...\n") != 0){
        printf("create thread error\n");
        return 1;
    }
    
    int ret = 0;
    sleep(1); //很重要,要让线程先分离,在等待
    
    if(pthread_join(tid, NULL) == 0){
        printf("pthread wait success\n");
        ret = 0;
    } else{
        printf("pthread wait failed\n");
        ret = 1;    
    }
    return ret;
}
[wz@192 Desktop]$ gcc -o test test.c -lpthread
[wz@192 Desktop]$ ./test
thread run ...

pthread wait failed

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1016873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

许可分析 license分析 第十七章

许可分析是指对软件许可证进行详细的分析和评估&#xff0c;以了解组织内部对软件许可的需求和使用情况。通过许可分析&#xff0c;可以帮助组织更好地管理和优化软件许可证的使用。以下是一些可能的许可分析方法和步骤&#xff1a; 软件许可证的云化管理&#xff1a;将许可证管…

如何删除清理Mac“其他”文件并删除它

当我们通过「关于本机」>「存储空间」查看硬盘的空间占用情况时。系统会将存储空间根据不同文件类别所占的空间大小显示在条状图上&#xff0c;大部分类型看文字都比较好理解&#xff0c;但对于“其他”这一类很多小伙伴都感觉很困惑&#xff0c;会产生一些问题如&#xff1…

Mac FoneLab for Mac:轻松恢复iOS数据,专业工具助力生活

如果你曾经不小心删除了重要的iOS数据&#xff0c;或者因为各种原因丢失了这些数据&#xff0c;那么你一定知道这种痛苦。现在&#xff0c;有一个名为Mac FoneLab的Mac应用程序&#xff0c;它专门设计用于恢复iOS数据&#xff0c;这可能是你的救星。 Mac FoneLab for Mac是一种…

MySQL数据库详解 二:数据库的高级语言和操作

文章目录 1. 克隆表 ---- 将数据表的数据记录生成到新的表中1.1 方式一&#xff1a;先创建新表&#xff0c;再导入数据1.2方式二&#xff1a;创建的时候同时导入 2. 清空表 ---- 删除表内的所有数据2.1 delete删除2.2 truncate删除&#xff08;重新记录&#xff09;2.3 创建临时…

基于Java+SpringBoot+Vue的大学生线上心理咨询系统(可随意更改项目主题如医院预约、店铺预约、专家挂号、在线咨询等)

大学生线上心理咨询室系统 一、前言二、我的优势2.1 自己的网站2.2 自己的小程序&#xff08;小蔡coding&#xff09;2.3 有保障的售后2.4 福利 三、开发环境与技术3.1 MySQL数据库3.2 Vue前端技术3.3 Spring Boot框架3.4 微信小程序 四、功能设计4.1 主要功能描述 五、系统实现…

确认过眼神,你就是我心中的【理想型】API!

API作为开发者友好的Friend凭借信息直达、灵活便捷、简单高效的特点&#xff0c;成为了商户绝佳的“资源连接利器”&#xff0c;也是跨境支付过程的“基石堡垒”&#xff0c;通过以上全面的释义&#xff0c;你清晰了解API的作用了吗&#xff1f; 但API与全球电子商户的相遇过程…

《ADS2011射频电路设计与仿真实例》第一章—第六章用ads2017跟做的不同操作

我用的是ads2017&#xff0c;可能是因为版本原因&#xff0c;有些操作和书上的不一样 1.P69 Smith chart utility中&#xff0c;若要调节各曲线圆系的线条颜色&#xff0c;书上写的“执行菜单命令【circles】→【colors】”应该是【view】→【colors】 2.P83 要用微带线&…

Pycharm 2023 年下载、安装教程,好用的插件,附详细图文

文章目录 一、pycharm安装教程二、常用插件推荐安装方法插件介绍1、Material Theme UI Lite2、Chinese (Simplified) Language Pack / 中文语言包3、Statistic4、Json Parser5、Tabnine&#xff08;强烈推荐&#xff09;6、Rainbow Brackets&#xff08;推荐&#xff09;7、Ind…

友善Nona Pi开发板ubuntu22.04系统用Python3.8.17的pip安装PyQt5.15.2时报错“Q_PID”这个宏未定义的一种解决办法

安装命令&#xff1a; pip install PyQt55.15.2 --config-settings --confirm-license --verbose -i https://mirrors.aliyun.com/pypi/simple/ 遇到出错&#xff1a; 如图&#xff1a; 分析具体错误内容&#xff1a; These bindings will be built: Qt, QtCore, QtNetwo…

Draw.io for Mac:强大流程图绘制工具,让你的想法迅速可视化

对于需要经常处理复杂概念和流程的专业人士和爱好者来说&#xff0c;一个优秀的图形设计工具是必不可少的。今天&#xff0c;我们将为您介绍一款流程图绘制神器——Draw.io for Mac。这款应用具备易于使用的界面和强大的功能&#xff0c;可以帮助您快速创建各种精美的流程图。 …

2023CSP游寄

初赛 DAY -2 才刚考开学测就来初赛。 复赛之后就是月测&#xff0c;这就是初三吗。 初中最后一次 CSP&#xff0c;如果 S 没一等就得摆烂了。希望别因为各种原因爆炸。 中午下午借着刷初赛题的名义摆烂&#xff0c;半道题都没写。 CSP2023RP 初赛 DAY -1 看我发现了什么。…

项目实战-day1.0

软件开发整体介绍 软件开发流程 需求分析--需求规格说明书、产品原型 设计--UI设计、数据库设计、接口设计 编码--项目代码、单元测试 测试--测试用例、测试报告 上线运维--软件环境安装、配置 角色分工 软件环境 开发环境&#xff1a;开发人员在开发阶段使用的环境&am…

FactoryTalk View Studio

由于项目需要&#xff0c;学习了FactoryTalk View Studio的一些操作&#xff0c;这里记录一下&#xff0c;方便以后查阅&#xff0c;并且随着项目的学习&#xff0c;随时更新。 FactoryTalk View Studio FactoryTalk View Studio 安装新建一个View Site Edition工程在工程中新建…

Bash脚本自学 - 输入输出重定向

1. 输入输出重定向 首先&#xff0c;我们有一个文件 hello.txt&#xff0c; Hello World! Good day to you 在指令行中输入&#xff1a; wc -w hello.txt输出为&#xff1a; 6 hello.txt wc -w 是用于统计命令行参数中指定文件的字数&#xff08;单词数&#xff09;。 如果…

2023年奢侈品行业研究报告

第一章 行业概况 1.1 定义和分类 奢侈品行业是一个专门生产和销售高价值、高品质、具有独特性和稀缺性商品的行业。这些商品往往超出了人们的基本生活需求&#xff0c;更多地与特定的社会地位、身份认同和审美价值有关。奢侈品不仅仅是物质的&#xff0c;它们往往承载着品牌的…

KubeSphere:登录错误,token failed, reason: getaddrinfo EAI_AGAIN ks-apiserver

1.问题现象: 2.问题解决&#xff1a; [rootk8s-node1 ~]# kubectl get pods --all-namespaces [rootk8s-node1 ~]# kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS …

代码随想录 --- day21 --- 530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数 、236. 二叉树的最近公共祖先

530.二叉搜索树的最小绝对差 题目中要求在二叉搜索树上任意两节点的差的绝对值的最小值。 注意是二叉搜索树&#xff0c;二叉搜索树可是有序的。 遇到在二叉搜索树上求什么最值啊&#xff0c;差值之类的&#xff0c;就把它想成在一个有序数组上求最值&#xff0c;求差值&…

高速DSP系统设计参考指南(一)高速DSP设计面临的挑战

&#xff08;一&#xff09;高速DSP设计面临的挑战 1. 概述2. 一般挑战3. DSP音频系统的挑战4. 视频系统的挑战5. DSP通信系统面临的挑战 资料参考来自TI官网和网络。 1. 概述 DSP芯片&#xff0c;也称数字信号处理器&#xff0c;是一种具有特殊结构的微处理器。DSP芯片的内部…

LabVIEW开发锅炉汽包水位的监督控制和模拟

LabVIEW开发锅炉汽包水位的监督控制和模拟 控制锅炉汽包液位对于机械的安全和设备的保护至关重要。滚筒液位控制器的工作是将滚筒液位提高到指定的设定点&#xff0c;并保持在那里&#xff0c;同时保持一致的蒸汽负荷。锅炉管可能会因该水平急剧下降而暴露&#xff0c;这会导致…

Mybatis常见面试题总结

梳理面试过程中Mybatis相关的常见问题。为保证知识点覆盖&#xff0c;参考了《Mybatis从入门到精通》、《深入浅出Mybatis技术原理与实战》、《Mybatis技术内幕》等书籍。 Mybatis 简介 Mybatis 是一款优秀的持久层框架(ORM框架)&#xff0c;它支持自定义SQL、存储过程以及高…