线程控制及线程底层原理

news2024/12/1 0:47:38

thread id 本质是一个地址。

以十六机制打印id。

 线程终止的两种方法。

1.直接return;

2.pthread_exit();

注意exit()是用来终止进程的,不能用于线程。

那怎么获取线程的返回值呢?

首先,和进程一样,线程退出也需要等待,不然也会导致僵尸问题。

int pthread_join(pthread_t thread, void **retval);
args:
    pthread_t thread: 被连接线程的线程号
    void **retval : 指向一个指向被连接线程的返回码的指针的指针
return:
    线程连接的状态,0是成功,非0是失败 

#include<iostream>
#include<string>
#include<functional>
#include<vector>
#include<pthread.h>
#include<unistd.h>
#include<time.h>
using namespace std;
using func_t=function<void()>;
const int threadnum=5;
class ThreadData
{
    public:
    ThreadData(const string&name,const uint64_t&ctime,func_t f)
    :threadname(name)
    ,createtime(ctime)
    ,func(f)
    {}
    public:
    string threadname;
    uint64_t createtime;
    func_t func;
};
string to_Hex(pthread_t tid)
{
    char id[64];
    snprintf(id,sizeof id,"0x%x",tid);
    return id;
}
void *ThreadRoutine(void*args)
{
    int a=2;
    ThreadData*td=static_cast<ThreadData*>(args);
    while(a--)
    {
        cout<<"I am new Thread  "<<td->threadname<<' '<<td->createtime<<' '<<to_Hex(pthread_self())<<' '<<endl;
        td->func();
        // if(td->threadname=="thread-4")
        // {
        //     a/=0;
        // }
        sleep(1);
    }
    pthread_exit((void*)"thread 1");

}
void print()
{
    cout<<"我是线程执行的大任务的一部分"<<endl;
}

int main()
{
  
    pthread_t tid;
    char threadname[64];
    snprintf(threadname,sizeof threadname,"%s-%d","thread",1);
    ThreadData*td=new ThreadData(threadname,uint64_t(time(nullptr)),print);
    pthread_create(&tid,nullptr,ThreadRoutine,td);
    cout<<to_Hex(tid)<<endl;
    void *ret=nullptr;
    int n=pthread_join(tid,&ret);
    cout<<"main thread done"<<"   n:   "<<n<<' '<<(const char*)ret<<endl;
    return 0;

}

我们要要得到为void*的返回值,那么就需要传入void**,所以是&ret。 

线程的等待不需要像进程一样获取异常,因为一出问题就挂。

#include<iostream>
#include<string>
#include<functional>
#include<vector>
#include<pthread.h>
#include<unistd.h>
#include<time.h>
using namespace std;
using func_t=function<void()>;
const int threadnum=5;
class ThreadData
{
    public:
    ThreadData(const string&name,const uint64_t&ctime,func_t f)
    :threadname(name)
    ,createtime(ctime)
    ,func(f)
    {}
    public:
    string threadname;
    uint64_t createtime;
    func_t func;
};
class ThreadReturn
{
    public:
    ThreadReturn(pthread_t id,int code,string info)
    :_id(id)
    ,_code(code)
    ,_info(info)
    {}
    public:
    pthread_t _id;
    int _code;
    string _info;
};
string to_Hex(pthread_t tid)
{
    char id[64];
    snprintf(id,sizeof id,"0x%x",tid);
    return id;
}
void *ThreadRoutine(void*args)
{
    int a=2;
    ThreadData*td=static_cast<ThreadData*>(args);
    while(a--)
    {
        cout<<"I am new Thread  "<<td->threadname<<' '<<td->createtime<<' '<<to_Hex(pthread_self())<<' '<<endl;
        td->func();
        // if(td->threadname=="thread-4")
        // {
        //     a/=0;
        // }
        sleep(1);
    }
    ThreadReturn* ret=new ThreadReturn(pthread_self(),10,"quit normal");
    //pthread_exit((void*)ret);
    return ret;

}
void print()
{
    cout<<"我是线程执行的大任务的一部分"<<endl;
}


int main()
{
  
    pthread_t tid;
    char threadname[64];
    snprintf(threadname,sizeof threadname,"%s-%d","thread",1);
    ThreadData*td=new ThreadData(threadname,uint64_t(time(nullptr)),print);
    pthread_create(&tid,nullptr,ThreadRoutine,td);
    cout<<to_Hex(tid)<<endl;
    void *ret=nullptr;
    int n=pthread_join(tid,&ret);
    ThreadReturn*r=static_cast<ThreadReturn*>(ret);
    //cout<<"main thread done"<<"   n:   "<<n<<' '<<(ThreadReturn*)ret<<endl;
    cout<<r->_id<<' '<<r->_code<<' '<<r->_info<<endl;
    return 0;

}

线程的返回值,可以是结构化的数据。

线程的等待默认是joinable的,如果阻塞等待失败可能会有僵尸问题。

我们可以把它设置成分离状态。

实际上,像是QQ这样的软件,死循环运行才是常态。

为了让线程分离,我们可以调用pthread_detach函数。

  • 函数描述:实现线程分离
  • 函数原型:int pthread_detach(pthread_t thread);
  • 函数返回值:成功:0;失败:错误号

也可用pthread_cancel(pthread_t tid)直接取消进程。 

pthread原生线程库中会有一个存储tcb(线程控制模块)的数组,用户和系统之间,线程与lwp一一对应。

tcb组成:

1、threadID:线程的唯一标识。
2、status:线程的运行状态
3、register:线程关于CPU中寄存器的情况
4、PC程序计数器:线程执行的下一条指令的地址
5、优先级:线程在操作系统调度的时候的优先级
6、线程的专属存储区:线程单独的存储区域
7、用户栈:线程执行的用户方法栈,用来保存线程当前执行的用户方法的信息
8、内核栈:线程执行的内核方法栈,用来保存线程当前执行的内核方法信息

线程的上下文是由操作系统以轻量级进程的方式保存在pcb之中的。

栈的寄存器只有一套,怎么兼顾多个线程呢?

创建轻量级进程用到的函数,是pthread_create()底部封装的函数。

第一个参数是回调方法, 第二个参数是用户传入的栈,允许用户指定栈。

每个新线程的栈,在库中维护。

C语言缓冲区,每一个C语言文件对象中会存在一个缓冲区,所以我们说缓冲区是C语言维护的,

说白了,就是在C库中维护的。

所以,一个库可以对一块内存空间进行维护。

同样的,pthread库也是库,在库中实现pthread_create的时候,内部包的就是clone函数。

在调它之前,先malloc申请空间,然后把空间传给stack,充当新线程的栈。

库一般被加载到堆栈之间的共享区。

pthread一旦被加载到内存中,要经过页表映射,最终映射到当前进程的共享区。

那么线程的栈在哪里呢?

pthread内部会帮我们new出来一段空间,把堆空间的地址写到pthread库里面,在库里用指针维护,线程退出时把空间释放掉就行。

默认地址空间中的栈由主线程使用,这样,可以保证每一个新线程都可以保存要执行的方法,要传递的参数以及动态运行时的临时变量。  

和可执行程序一样,pthread库会通过页表从内存映射到地址空间堆栈之间的共享区。

创建线程的时候,在正文代码区,直接跳转到共享区的库里,执行创建线程的函数,然后返回。

而线程库是共享的,所以,内部要管理整个系统,多个用户启动的所有的线程。

如图,共享区里有动态库和有线程结构体组成的数组。

调用线程时,将结构体中的数据传入clone函数。 

也可调用pthread_join从中获取返回值。

tid代表线程属性集合在库中的地址。

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

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

相关文章

Python 入门指南(一)

原文&#xff1a;zh.annas-archive.org/md5/97bc15629f1b51a0671040c56db61b92 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 前言 这个学习路径帮助你在 Python 的世界中感到舒适。它从对 Python 的全面和实用的介绍开始。你将很快开始在学习路径的第一部分编写程序…

2024年阿里云4核8G配置云服务器价格低性能高!

阿里云4核8G服务器租用优惠价格700元1年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采用Intel(R) Xeon(R) Platinum处理器&#xff0c;阿里云优惠 aliyunfuwuqi…

基于docker的Jenkin的服务平台搭建

项目拓扑图 项目环境: jenkins-2.440 sonarqube-9.9.4 apache-maven-3.9.6 gitlab-ce-12.4.2 java17 docker20 harbor.v2.6.0 centos7.9 项目目的: 模拟企业构建一个流行的持续集成和持续部署环境,可以更轻松地创建和管理构建环境&#xff0c;实现自动化构建和部署应用程序的…

大模型开发轻松入门——(1)从搭建自己的环境开始

pip install openai import openai import osfrom dotenv import load_dotenv, find_dotenv _ load_dotenv(find_dotenv())openai.api_key os.getenv(OPENAI_API_KEY)

3d模型怎么全是网格?---模大狮模型网

在进行3D建模或场景设计时&#xff0c;有时会遇到一个普遍问题&#xff0c;即所见的3D模型表面全是由网格组成&#xff0c;而没有显示实际的表面纹理或颜色。这可能会导致困惑和挫败感&#xff0c;阻碍项目的进展。本文将深入探讨这一现象背后的原因&#xff0c;并提供多种解决…

2024九章云极DataCanvas智算操作系统新品发布会震撼来袭!

从大模型到智能算力&#xff0c;从“数字中国”到“新质生产力”……在技术突破和时代引领双轮驱动下&#xff0c;人工智能技术应用不断刷新全社会的认知&#xff0c;人工智能产业机遇席卷而来、发展将颠覆想象。随着AIGC和大模型的快速发展&#xff0c;建设拥有“卓越算力”和…

Chrome修改主题颜色

注意&#xff1a;自定义Chrome按钮只在搜索引擎为Google的时候出现。

如何鉴别品深茶叶的真伪?

鉴别品深茶叶的真伪可以通过以下三点进行判断&#xff1a;第一是看&#xff0c;观察茶叶的颜色和形状是否自然&#xff1b;第二是闻&#xff0c;感受茶叶的香气是否纯净&#xff1b;第三是泡&#xff0c;品尝茶汤的味道是否醇厚。最好的方式还是通过官方访问进行查询&#xff0…

Linux系统——Elasticsearch企业级日志分析系统

目录 前言 一、ELK概述 1.ELK简介 2.ELK特点 3.为什么要使用ELK 4.完整日志系统基本特征 5.ELK工作原理 6.Elasticsearch介绍 6.1Elasticsearch概述 6.2Elasticsearch核心概念 7.Logstash介绍 7.1Logstash简介 7.2Logstash主要组件 8.Kibana介绍 8.1Kibana简介 …

划重点!免费SSL证书要慎用

HTTPS协议逐渐成为当下网络传输协议的主流方式&#xff0c;这一点为人共知&#xff0c;也正是基于这一点&#xff0c;SSL证书的使用越来越被网站所接受。同时&#xff0c;SSL证书市场产品种类繁多&#xff0c;从免费版本到价格不等的收费版都有&#xff0c;不少用户考虑成本等因…

【网络编程】web服务器shttpd源码剖析——命令行和文件配置解析

hello &#xff01;大家好呀&#xff01; 欢迎大家来到我的网络编程系列之web服务器shttpd源码剖析——命令行解析&#xff0c;在这篇文章中&#xff0c;你将会学习到在Linux内核中如何创建一个自己的并发服务器shttpd&#xff0c;并且我会给出源码进行剖析&#xff0c;以及手绘…

QTableWidget的使用案例

QTableWidget的使用案例 创建QTableWidget m_table_widget new QTableWidget(this);m_table_widget->setObjectName("TableWidget");m_table_widget->setShowGrid(false);m_table_widget->setSortingEnabled(true);m_table_widget->setEditTriggers(QAb…

EcoVadis评估是什么?EcoVadis评估的步骤有哪些

EcoVadis评估是一种针对供应链中各个环节的环境和社会责任进行评估的工具。其评估范围广泛&#xff0c;涵盖了环境、劳工与人权、商业道德和可持续采购等多个领域。通过收集企业的公开信息、企业提供的数据和自我评估问卷等方式&#xff0c;EcoVadis能够为企业提供一个全面的可…

C++ 之 newmat 矩阵运算库使用笔记

文章目录 Part.I IntroductionChap.I newmat 简介 Part.II 安装与编译Chap.I 直接使用源码Chap.II 基于 CMake 使用源码Chap.III 编译成库 Part.III 关于矩阵的构造与运算Chap.I 矩阵的构造与初始化Chap.II 矩阵的运算Chap.III 矩阵维数和类型的更改Chap.IV 矩阵最值统计 Refer…

Spring容器结构

文章目录 1.基本介绍1.Spring5官网2.API文档3.Spring核心学习内容4.几个重要概念 2.快速入门1.需求分析2.入门案例1.新建Java项目2.导入jar包3.编写Monster.java4.src下编写Spring配置文件1.创建spring配置文件&#xff0c;名字随意&#xff0c;但是需要放在src下2.创建Spring …

蓝桥杯(基础题)

试题 C: 好数 时间限制 : 1.0s 内存限制: 256.0MB 本题总分&#xff1a;10 分 【问题描述】 一个整数如果按从低位到高位的顺序&#xff0c;奇数位&#xff08;个位、百位、万位 &#xff09;上 的数字是奇数&#xff0c;偶数位&#xff08;十位、千位、十万位 &…

张大哥笔记:电脑周边的10大刚需创业小项目

hello&#xff0c;大家好&#xff0c;我是张大哥&#xff0c;今天一口气给大家分享围绕电脑周边的10大刚需创业小项目&#xff0c;本文章旨在帮助大家如何快速切入到细分领域里面搞钱&#xff01; 如何赚钱&#xff0c;无非就是解决人群痛点&#xff0c;你要懂得根据用户痛点去…

知识跟踪模型GraphKT

1 知识跟踪Knowledge Tracing的概念 知识跟踪可以用来解决自适应学习问题。如何通过与教学材料的在线互动来有效地跟踪学生的学习进展&#xff1f;知识跟踪可用于量化学生的知识状态&#xff0c;即对教材所涉及的技能掌握水平。用于评估和模拟学生随着时间推移对技能的认知掌握…

双指针的引入和深入思考(持续更新中)

目录 1.引入双指针 2.使用场景 3.例题引入 1.引入双指针 当我们需要维护某个区间性质的或者是求满足某些性质的区间的长度时&#xff0c;对于一个区间是由左右端点的&#xff0c;我们有简单的枚举左右端点的O()的时间的做法&#xff0c;当时在大多数题目中是不可行的&#…

4核8G配置服务器多少钱?2024年阿里云服务器700元1年价格便宜

4核8G配置服务器多少钱&#xff1f;2024年阿里云服务器700元1年价格便宜。阿里云4核8G服务器租用优惠价格700元1年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采…