初始Liunx线程

文章目录

  • 前言
  • 1.初始Liunx下线程
  • 2.关于虚拟地址的补充知识
  • 3.线程的相关特点
    • 1.线程的优点
    • 2.线程的缺点
    • 3.线程异常
    • 4.线程和进程的比较
  • 4.线程相关操作接口
    • 线程控制相关接口
  • 5.关于线程id的理解

前言

本文主要是对Liunx之下线程的前置知识铺垫,同时也是对之前进程的相关知识的补充。

1.初始Liunx下线程

在一些教材中线程被定义为是一个执行分支,执行粒度比进程更细,调度成本更低。内核观点认为:进程是分担系统资源的基本实体,线程是cpu调度的基本单位。这些是操作系统设计哲学,为啥要细分出线程呢?其实这是为了减少一些不必要的因为进程切换造成的系统消耗,我们学过计算机都是知道程序局部性原理,cpu当前的访问的代码和当前访问的代码的周边代码后面会有较大的概率被重新访问到,因此内存中有个叫做cache缓存的硬件。当CPU频繁的切换的进程,cache中之前进程的相关数据也被清理需要重新加载当前进程相关数据。这就大大较低了cpu执行效率,同时切换进程时,cpu中相关寄存器也需要进行切换指向新进程的相关代码数据和进程pcb,这也是一种消耗。由此可以被划分为粒度更细的线程,从而提高整机执行效率。线程同样需要被操作系统所管理起来,因此也需要对应的数据结构将其描述组织起来,不同的操作系统有不同的设计方案,在Liunx中线程是复用了进程pcb的结构和进程调度算法,这样无疑会让线程的结构相对来说更加简单,便于维护,同样执行效率也会更高。Windows中线程控制块Tcb是重新设计了一套数据结构和管理方案,因此相对来说Windows中的线程更复杂,执行效率也会更低一点。Linux中线程被称为轻量级进程。

代码示例

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
#include<pthread.h>
void *thread1_run(void *args)
{
    while(1)
    {
        printf("我是线程1,我正在运行\n");
        sleep(1);
    }
}
void *thread2_run(void *args)
{
    while(1)
    {
        printf("我是线程2,我正在运行\n");
        sleep(1);
    }
}

int main()
{
   pthread_t t1,t2;
   pthread_create(&t1,NULL,thread1_run,NULL);
   pthread_create(&t2,NULL,thread2_run,NULL);
   while(1)
   {
     printf("我是主线程,我正在运行\n");
     sleep(1);
   }
}

在这里插入图片描述

当我们将上述代码运行起来,发现确实是3个执行流,执行了3个while循环。我们可以看到这3个线程的PID是一样的,也就是这3个执行流是同属于一个进程的。Liunx中线程只有主次之分,主线程的LWP和PID是一样的,这个LWP就是线程的tid,当程序就没有其他执行流的时候也就只有一个进程(轻量级进程),同样的也就是一个所谓的线程。这就和之前的进程相关的知识并不冲突。

在这里插入图片描述

Liunx中的线程和进程应该如图的样式,Linux中进程应该是众多执行流和系统为其分配的资源的合集。

2.关于虚拟地址的补充知识

之前,在介绍磁盘文件相关内容的时候提到过,内存与外设进行IO交换的时候都是以4KB大小的数据块为单位的,这样可以提搞整机执行效率。当往内存中加载的数据不足4kb时我们根据程序局部性原理将其周边的数据也加载到内存中,从而提高执行效率。进程相关代码数据是通过页表和物理内存建立联系的,其实页表可以细分为页目录和页表项。以32位机器为例,前10位表示页目录,中间10为表示页表项,后面12用来找到对应的数据块。

在这里插入图片描述

页表的寻址方式就是通过页目录先定位到页表项,这样就相当于找到了要访问的数据块起始地址,后面12位就是数据块内的偏移的地址了,通过这种方式可以准确找到任何一个数据块的块内地址。这种寻址方式就是基地址加偏移量,这样设计页表可以大大节省空间,不用担心因为光是页表就会造成地址不够的情况。

3.线程的相关特点

1.线程的优点

1.创建一个新线程的代价要比创建一个新进程小得多.
2.与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多,线程占用的资源要比进程少很多,能充分利用多处理器的可并行数量.

2.线程的缺点

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

3.线程异常

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

4.线程和进程的比较

线程是共用进程地址空间,多线程中很多资源是共享的。但是有一部资源的线程独有的:线程ID,一组寄存器(上下文数据),栈等等。进程的多个线程共享 同一地址空间,因此Text Segment、Data Segment都是共享的,如果定义一个函数,在各线程中都可以调用,如果定义一个全局变量,在各线程中都可以访问到,除此之外,各线程还共享以下进程资源和环境:文件描述符表,每种信号的处理方式(SIG_ IGN、SIG_ DFL或者自定义的信号处理函数),当前工作目录,用户id和组id.

4.线程相关操作接口

Liunx下,没有真正意义上的线程,而是用进程模拟线程(LWP)。因此Liunx不会直接提供创建线程的系统调用,它最多给我们提供创建轻量级进程的接口。因此Linux中有专门的线程库将相关接口进行封装,给用户提供进行线程控制的接口。我们在使用线程库的时候必须加上-lpthread选项。

在这里插入图片描述

线程控制相关接口

线程创建接口:pthread_create

在这里插入图片描述

第一个参数线程id ,第二个参数是设置线程相关属性的,使用默认属性可设置为nullptr,第三个参数函数地址,表示线程启动后要执行的函数,第四个参数是作为传递给线程执行函数的参数。线程创建成功返回0,失败返回-1。

之前学习进程的时候,我们知道进程是需要等待的,以便于知道进程执行情况。如果没有进程等待就可以会出现僵尸进程,同样的线程一般来说需要等待的,以便于让我们知道这个线程的执行结果。

pthread_join函数线程等待

在这里插入图片描述

第一个参数是线程id,第二个参数是输出型参数,用来获得线程退出情况。

线程退出有以下几种方式,调用exit函数退出进程,线程自然也就退出了。在线程执行函数中直接return也可以退出。另外还有两个函数也可以退出线程。

pthread_exit函数用于直接退线程,参数也是输出型参数,相当于return值。

在这里插入图片描述

pthread_cancel函数取消一个正在运行的线程,这个时候获得的线程退出码是为2的。

在这里插入图片描述

pthread_self函数是一个无参函数,是用来获得线程id的。哪个线程调用它,就获得哪个线程的id。

在这里插入图片描述

代码示例

#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
#include<pthread.h>
#include<iostream>
#include<string>
using namespace std;
#define NUM 10

class ThreaData
{  
    public:
    ThreaData(const string&name,int id)
    :_name(name),_id(id){}
    ~ThreaData(){}
    public:
    string _name;
    int _id;

};
void *thread_run(void *args)
{
    ThreaData*td=static_cast<ThreaData*>(args);
    while(1)
    {
     cout<<"thread is runnig name"<<td->_name<<"id :"<<td->_id<<endl;
     sleep(4);
     break;
    }
    delete td;
    pthread_exit((void*)2);
}


int main()
{
   pthread_t tids[NUM];
   for(int i=0;i<NUM;i++)
   { 
     char tname[64];
     snprintf(tname,64,"thread-%d",i+1);
     ThreaData* td=new ThreaData(tname,i+1);
     pthread_create(tids+i,nullptr,thread_run,td);
     sleep(1);
   }
   void* ret=nullptr;
   for(int i=0;i<NUM;i++)
   {
    int n=pthread_join(tids[i],&ret);
    if(n!=0)
    {
        cout<<"thred quit: "<<(int64_t)ret<<endl;
    }
   }
   cout<<"thread quit!"<<endl;
   return 0;
}

在这里插入图片描述

上述代码已经调用了相关接口,我们可以让线程执行流去做对应的任务,我们也可获取的线程相关的执行结果。

线程分离

我们主线程在等待其他线程的时候就处于阻塞状态的,如果我们不关心线程的执行结果,不想让主线程被阻塞,我们可以将线程进行分离,由系统回收线程相关资源。pthread_detach就是线程分离函数,注意当一个线程被分离以后就不能在join了。

在这里插入图片描述

5.关于线程id的理解

我们创建线程是通过线程库来创建的。线程库的动态库,需要加载的内存中。线程库中做好了对线程描述组织工作,线程TCP控制块已经被库管理好了。线程PID实际上就是线程库中对应的线程结构的起始地址。这样在上层用户直接使用提供好的相关接口操作线程即可。

在这里插入图片描述

我们看到的LWP是给用户看的id,看起来比较短。但是这个pthread_t id是库中线程控制块的起始地址因此看起来比较长。所以线程都有自己的独立栈,主线程是使用的系统栈,新线程是使用库中的栈。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

EasyCVR如何实现国标级联无人机推送的RTMP推流通道?

EasyCVR视频融合平台基于云边端一体化架构&#xff0c;可支持多协议、多类型设备接入&#xff0c;包括&#xff1a;NVR、IPC、视频编码器、无人机、车载设备、智能手持终端、移动执法仪等。平台具有强大的数据接入、处理及分发能力&#xff0c;可在复杂的网络环境中&#xff0c…

ZYNQ——脉宽调制之呼吸灯实现

文章目录 原理简介实验代码软件仿真板上验证 原理简介 呼吸灯的实现过程就是把不同占空比的脉冲输出后加在LED上&#xff0c;LED灯就会显示不同的亮度&#xff0c;通过不断地调节方波的占空比&#xff0c;LED灯的亮度也会跟着变化&#xff0c;看起来就像是“呼吸”一样。 要得…

爬虫小白入门在服务器上-部署爬虫或者开服务接口并供给他人访问

目录 一、准备工作-服务器1、先准备一个服务器&#xff08;以阿里云为例子&#xff09;2、开通服务端口号访问权限 二、准备工作-Xshell登录服务器1、xshell基本登录操作2、xftp基本操作 三、部署代码到服务器上1、部署一个python爬虫脚本在服务器上定时运行等2、部署一个pytho…

【面试常见】JS继承与原型、原型链

前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 在 JavaScript 中&#xff0c;继承是实现代码复用和构建对象关系的重要概念。本文将讨论原型链继承、构造函数继承以及…

SONY索尼MP4视频变RSV文件修复方法

索尼MP4变RSV的原因分析 索尼新型号相机或者摄像机&#xff0c;如SONY A7S3&#xff0c;A7M4&#xff0c;FX3, FX6, FX9等&#xff0c;如果录像过程中有发生如下异常情况&#xff0c;如断电&#xff0c;死机&#xff0c;电量不足&#xff0c;机器摔倒&#xff0c;非常规操作&a…

【接口测试】Postman —— 接口测试知识准备

1.0 前言 ​应用程序编程接口&#xff08;Application Programming Interface, API&#xff09;是这些年来最流行的技术之一&#xff0c;强大的Web应用程序和领先的移动应用程序都离不开后端强大的API。API技术的应用给系统开发带来了便利&#xff0c;但也对测试人员提出了更高…

CentOS7下载并安装mysql-8.0.33

CentOS7下载并安装mysql-8.0.33 一、官网下载mysql-8.0.33 MySQL下载路径 MySQL :: Download MySQL Community Server 自己百度mysql官网下载的话直接按照完整路径指示下载即可&#xff0c;如果点击上面的连接下载mysql的话&#xff0c;直接按照4、5、6步骤选择适合自己linu…

旅游卡景区购票小程序开发定制

旅游业的蓬勃发展&#xff0c;越来越多的景区开始推出自己的旅游卡&#xff0c;以吸引更多的游客前来观光。同时&#xff0c;为了更加便捷地服务游客&#xff0c;许多景区也开始启用小程序来进行门票售卖和游客管理。针对这种情况&#xff0c;专业的小程序开发公司推出了定制旅…

自定义注解,基于redis实现分布式锁

一、如何实现自定义注解 1.1、注解的基础知识 实现自定义注解其实很简单&#xff0c;格式基本都差不多。也就参数可能变一变。 Retention&#xff1a;取值决定了注解在什么时候生效&#xff0c;一般都是取运行时&#xff0c;也就是RetentionPolicy.RUNTIME。 Target&#xff…

初识Go语言25-数据结构与算法【堆、Trie树、用go中的list与map实现LRU算法、用go语言中的map和堆实现超时缓存】

文章目录 堆Trie树练习-用go中的list与map实现LRU算法练习-用go语言中的map和堆实现超时缓存 堆 堆是一棵二叉树。大根堆即任意节点的值都大于等于其子节点。反之为小根堆。   用数组来表示堆&#xff0c;下标为 i 的结点的父结点下标为(i-1)/2&#xff0c;其左右子结点分别为…

性能优化 :删除项目中没有引用关系的文件 useless-files-webpack-plugin

一般此类包不需要安装到项目中&#xff0c;减少node_modules体积&#xff08;以项目实际情况决定-S/-D&#xff09; npm i useless-files-webpack-plugin -S然后再vue.config.js中配置 const UselessFile require(useless-files-webpack-plugin) chainWebpack: config > …

【NLP模型】文本建模(2)TF-IDF关键词提取原理

一、说明 tf-idf是个可以提取文章关键词的模型;他是基于词频,以及词的权重综合因素考虑的词价值刻度模型。一般地开发NLP将包含三个层次单元:最大数据单元是语料库、语料库中有若干文章、文章中有若干词语。这样从词频上说,就有词在文章的频率,词在预料库的频率,文章在预…

SpringBoot3.0整合RocketMQ时出现未能加载bean文件

SpringBoot3.0整合RocketMQ时出现未能加载bean文件 问题 APPLICATION FAILED TO START Description: Field rocketMQTemplate in com.spt.message.service.MqProducerService required a bean of type ‘org.apache.rocketmq.spring.core.RocketMQTemplate’ that could not …

window debug ios webview

业务需求 在window上想要debug在ios的应用中的webview页面&#xff0c;毕竟页面是在安卓端和ios端都有webview的。安卓的页面使用edge的edge://inspect/#devices&#xff0c;手机开启调试模式就可以了。对于ios就没有办法&#xff0c;页面中已经使用了vconsole可以看到部分的信…

火山引擎 Iceberg 数据湖的应用与实践

在云原生计算时代&#xff0c;云存储使得海量数据能以低成本进行存储&#xff0c;但是这也给如何访问、管理和使用这些云上的数据提出了挑战。而 Iceberg 作为一种云原生的表格式&#xff0c;可以很好地应对这些挑战。本文将介绍火山引擎在云原生计算产品上使用 Iceberg 的实践…

XXX汽车ERP系统供应商索赔业务上线,助力业财数据快速闭环(投稿数据化月报四)

供应商三包索赔款项源起QMS质量系统&#xff0c;联动金税系统完成发票开具&#xff0c;最终在SAP系统中创建完成财务凭证。该流程上线前为手工操作&#xff0c;费时费力且效率低下容易出错。针对该业务现状&#xff0c;SAP与QMS业务顾问及开发团队组成开发小组&#xff0c;导入…

使用matplotlib制作动态图

使用matplotlib制作动态图 一、简介二、模块简介1. **FuncAnimation**类介绍2. 定义动画更新函数 三、使用matplotlib制作动画1.一步法制作动态图片2. 两步法制作动态图片 一、简介 matplotlib(https://matplotlib.org/)是一个著名的python绘图库&#xff0c;由于其灵活强大的…

计算机视觉 + Self-Supervised Learning 五种算法原理解析

计算机视觉领域下自监督学习方法原理 导语为什么在计算机视觉领域中进行自我监督学习&#xff1f; 自监督学习方法Generative methodsBEiT 架构 Predictive methodsContrastive methodsBootstraping methodsSimply Extra Regularization methods 导语 自监督学习是一种机器学习…

SQL Server SQL语句

在很多情况下&#xff0c;可以用CREATE TABLE语句创建数据表、使用ALTER TABLE语句修改表结构、使用DROP TABLE语句删除表&#xff1b; 可以使用CREATE DATABASE创建数据库、ALTER DATABASE修改文件或文件组、DROP DATABASE语句删除数据库&#xff1b; 1、数据定义语句&#x…

【MySQL】MySQL基本语句大全

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️MySQL】 文章目录 前言结构化查询语句分类MySQL语句大全&#x1f4da;DDL&#xff08;对数据库和表的操作&#xff09;&#x1f916;DQL&#xff08;查询语句&#xff09;&#x1f4bb;关键字&#x…