初始Liunx线程

news2024/11/27 8:43:29

文章目录

  • 前言
  • 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是库中线程控制块的起始地址因此看起来比较长。所以线程都有自己的独立栈,主线程是使用的系统栈,新线程是使用库中的栈。

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

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

相关文章

Spring Boot 中的认证是什么,如何使用

Spring Boot 中的认证是什么&#xff0c;如何使用 在 Web 应用程序中&#xff0c;认证是一项重要的安全措施。Spring Boot 提供了丰富的认证机制&#xff0c;可以帮助我们轻松地实现各种认证需求。本文将介绍 Spring Boot 中的认证是什么&#xff0c;以及如何使用 Spring Boot…

2023上半年软考系统分析师科目一整理-16

2023上半年软考系统分析师科目一整理-16 信息系统的性能评价指标是客观评价信息系统性能的依据&#xff0c;其中&#xff0c;&#xff08; &#xff09;是指系统在单位时间内处理请求的数量。 A.系统响应时间 B.吞吐量 C.资源利用率 D.并发用户数 运用互联网技术&#xff0c;在…

软件工程——第7章实现知识点整理

本专栏是博主个人笔记&#xff0c;主要目的是利用碎片化的时间来记忆软工知识点&#xff0c;特此声明&#xff01; 文章目录 1.实现由哪两个部分组成&#xff1f; 2.编码是什么&#xff1f;所选用的程序设计语言对程序的哪些特性有着深远影响&#xff1f; 3.软件测试在软件生…

旅游卡系统招募城市合伙人

旅游业的不断发展&#xff0c;旅游卡系统作为一种新型的旅游消费模式也逐渐被越来越多的人所认可。现在&#xff0c;许多旅游卡系统开始招募城市合伙人&#xff0c;以进一步拓展其市场。 旅游卡系统是一种可以将不同景区、景点门票进行整合&#xff0c;并提供折扣优惠的旅游…

谈谈mysql——Binlog的复制方式和解析技巧

mysql 我们先来看一下MySQL的基本架构&#xff0c;从大的方面来讲&#xff0c;一个server层&#xff0c;一个引擎层。server层就像一个接口&#xff0c;可以对接任何符合规定的引擎。具体的细节可以参考我之前写过的文章mysql的这些坑你踩过吗&#xff1f;快来看看怎么优化mys…

vue3+pinia用户信息持久缓存(token)的问题

vue3pinia用户信息持久缓存&#xff08;token)的问题 对博主来说&#xff0c;这是个相当复杂的问题。 当初在使用vue2vuex进行用户信息持久登录时&#xff0c;写了不下3篇博客&#xff0c;确实是解决了问题&#xff0c;博客链接如下 vue存储和使用后端传递过来的tokenvue中对…

动态规划之 509斐波那契数(第1道)

目录 题目&#xff1a;斐波那契数 &#xff08;通常用 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。 解法&#xff1a; 动态规划法&#xff1a; 题目&#xff1a;斐波那契数 &#xff08;通常用…

大象机器人人工智能套装2023版深度学习协作机器人、先进机器视觉与应用场景

引言&#xff1a; 介绍当前的版本 今天我们要介绍的是aikit2023&#xff0c;aikit2023是aikit的全新升级版。 AIkit 2023 是一套集视觉&#xff0c;定位抓取、自动分拣模块为一体的入门级人工智能套装。 该套装基于python平台&#xff0c;可通过开发软件实现机械臂的控制&am…

gitee提交项目失败记录:remote:error:hook declined to update refs/heads/master

问题描述&#xff1b; 今天修改了项目里面一些文件内容&#xff0c;结果提交的时候报错了&#xff0c;可以提交到本地仓库&#xff0c;但提交到中央仓库报如下异常&#xff0c;因此记录下&#xff0c;防止后面再遇到…… 解决办法&#xff1a; 登录gitee账号&#xff0c;在设置…

自定义MVC的进阶使用

文章目录 前言一、环境配置1.1 将框架打包成jar包1.2 将Jar包导入新项目1.3 将分页标签相关文件、及相关助手类导入1.4 配置文件 二、前后台编写2.1 实体类2.2 dao2.3 Servlet2.4 配置mvc.xml2.5 JSP2.6 运行结果 前言 通用增删改查、通用分页、XML解析反射建模&#xff0c;包…

【网络安全带你练爬虫-100练】第6练:内嵌发包提取数据

目录 一、分析目标&#xff1a; 二、代码实现 目标1&#xff1a;对于捕获的URL内嵌发包 目标2&#xff1a;找到电话和邮箱的位置 目标3&#xff1a;提取电话和邮箱 三、完整代码 四、网络安全小圈子 &#xff08;注&#xff1a;需要带上登录成功后的cookie发包&#xff…

Nginx部署前后端分离项目

dev.env.js解释 //此文件时开发环境配置文件 use strice//使用严格模式 const merge require(webpacl-merge)//合并对象 const prodEnv require(./prod.env)//导出 module.exports merge(prodEnv,{//合并两个配置文件对象并生成一个新的配置文件&#xff0c;如果合并的过程…

使用Postman做接口测试并生成接口测试报告

学习目标 1、录制脚本或使用手写url进行抓包 2、微信api接口&#xff08;可录制可手写&#xff09; 3、添加多 个标签&#xff0c;获取多个标签&#xff0c;编辑多个标签&#xff0c;删除多个标签&#xff01;&#xff01;&#xff01;&#xff08;csv格式&#xff09; 4、通过…

Java JDK 安装及环境配置教程

一、安装 1、安装包 jdk1.8安装包下载路径 2、创建一个英文的文件夹 注意&#xff1a;整个路径不要有中文、建议文件夹直接命名为JDK。 3、在该文件夹下创建两个空文件夹&#xff0c;分别为&#xff1a;jdk1.8 和 jre 其中jdk1.8 是我的JDK版本&#xff0c;这个可以自行改变。…

宝塔 安装/使用Jenkins-图文小白教程

一、Jenkins包下载 大家可以从Jenkins官网&#xff08;https://www.jenkins.io/&#xff09;根据自己的需要下载最新的版本。 但Jenkins官网下载较慢&#xff0c;容易造成下载失败。可以去国内的开源镜像网站下载Jenkins最新版本。目前博主使用的是清华大学的开源镜像网站&…

【spring创建对象方式】 and 【Java创建对象方式】

Spring创建对象方式 通过构造函数创建对象&#xff0c;通过静态工厂方式创建对象&#xff0c;通过实例工厂方式创建对象 1、通过构造函数创建对象 无参构造函数&#xff1a; 最基本的对象创建方式&#xff0c;只需要有一个无参构造函数&#xff08;类中没有写任何的构造函数…

excel 复制出来的数据内容自动带上空格

在excel中批量处理完了公式&#xff0c;想复制到navicat 或者文本编辑框里&#xff0c;发现都会自动带上双引号&#xff0c;但是excel 里是没有&#xff0c;查找了半天。 在excel里的文本如下所示 拷贝出来的结果如下所示&#xff1a; 经过检查发现原文中只要带有回车或者换行…

A40i Linux3.10开发板移植高精度定时器hrtimer驱动

目录 整编内核 修改Makefile文件 编译内核 生成.ko文件 应用层调用 这里使用整个编译内核的方式编译.ko文件。 整编内核 编写一个hrtimer_demo.c的驱动程序源码如下&#xff1a; #include <linux/module.h> #include <linux/kernel.h> #include <linux/i…

相机图片给 Livox 激光雷达点云赋色(python代码 单文件)

需要配置PCD文件路径, 图片路径,相机内参,相机和雷达的外参; 单文件, Windows , liunx 都可以运行。 雷达和相机外参如何标定请看我的另外一篇标定的代码文章。 效果如下图: 附上代码: # coding:utf-8import cv2 import numpy as np import open3d as o3ddef get_U…

记录一次在泛微OA中添加js代码块,限制开始日期时间不能大于等于结束日期时间

目标&#xff1a; 在选择流程后提交时&#xff0c;选择的开始日期、时间不能大于结束日期、时间选择的开始日期、时间不能等于结束日期、时间满足以上条件才可以提交 效果图&#xff1a; 在OA后台添加js代码的步骤&#xff0c;如下&#xff1a; 图一&#xff08;第1-5步参考图…