Linux--线程的分离、线程库的地址关系的理解、线程的简单封装(二)

news2024/10/6 4:11:28

线程系列:
线程的认识:讲解线程的概念和线程的基本控制

线程的分离

线程分离是指将一个线程从主线程中分离出来,使其能够独立运行。当一个线程被设置为分离状态时,它结束时系统会自动回收其资源,而不需要其他线程使用pthread_join()函数来等待其结束并手动回收资源。

设置线程分离的方法
使用pthread_detach()函数:在线程创建后,可以通过调用pthread_detach()函数来将线程设置为分离状态。这个函数是非阻塞式的,即调用后不会阻塞当前线程的执行。
在创建线程时设置分离属性:另一种方法是在创建线程时,通过pthread_create()函数的第二个参数(线程属性)来设置线程为分离状态。这种方法在创建线程时即指定了其分离属性,效率相对较高。

void* threadrun(void* args)
{
    string name = static_cast<const char *>(args);

    while(true)
    {
        sleep(1);
        cout<<"this is new thread:"<<name<<endl;
    }
}
int main()
{
	pthread_t tid;
    pthread_create(&tid, nullptr, threadrun, (void *)"thread 1");
    cout << "main thread wait block" << std::endl;
    pthread_join(tid, nullptr);
    cout << "main thread wait return"<<endl;
}

在这里插入图片描述

使用分离函数后:
在这里插入图片描述

再加个有限时间的循环看看:
在这里插入图片描述
对线程分离理解虽然新线程与主线程已经分离了,但它们仍然是同一进程中的执行流,如果程序使用时出现异常时(新线程或者主线程),那么两个程序都会终止;或者说主线程结束了,实际上就代表进程结束了;所以线程的分离仍然是在进程中进行的,受进程的影响

何时使用:当线程完成任务后不需要与其结果交付时;当线程在后台运行且不需要与主线程进行同步进行时;

注意:分离线程无法重新连接!而可连接线程可以分离,当只有在尚未开始运行之前

理解线程库的地址关系

在这里插入图片描述

在这里插入图片描述

线程栈

线程栈是与线程紧密相关的内存区域,用于存储线程的局部变量、函数调用的返回地址以及线程的执行上下文等信息每个线程都有自己独立的栈空间,这保证了线程之间的数据是隔离的,从而避免数据竞争和线程安全问题。

#include<iostream>
using namespace std;
#include<pthread.h>
#include<unistd.h>
void *threadrun1(void *args)
{  
    std::string name = static_cast<const char *>(args);
    int g_val=100;
    while(true)
    {
        sleep(1);
        printf("%s, g_val: %lu, &g_val: %p\n", name.c_str(), g_val--, &g_val);
    }
    return nullptr;
}

void *threadrun2(void *args)
{
    std::string name = static_cast<const char *>(args);
    int g_val=100;
    while(true)
    {
        printf("%s, g_val: %lu, &g_val: %p\n", name.c_str(), g_val--, &g_val);
        sleep(1);
    }
    return nullptr;
}

int main()
{
    pthread_t tid1;
    pthread_t tid2;
    pthread_create(&tid1, nullptr, threadrun1, (void *)"thread 1");
    pthread_create(&tid2, nullptr, threadrun2, (void *)"thread 2");

    pthread_join(tid1, nullptr);
    pthread_join(tid2, nullptr);
}

通过两个新线程都创建一个局部变量(变量名相同),比较它们的地址;
在这里插入图片描述
可以看到g_val在各自线程是不一样的,地址也是不同的;

线程局部存储(TLS)

线程局部存储(TLS)是一种机制,允许每个线程拥有自己的私有数据副本,即使不同线程执行相同的代码,TLS变量与常规全局变量是不同的,因为每个线程堆TLS变量的访问都是独立的。

一般适用于:

  • 线程特定数据:当某些数据只对特定线程有意义,并且需要在线程内保持状态时,可以使用线程局部存储。
  • 全局状态隔离:通过将全局状态分离为每个线程的私有副本,可以提高并发性能,避免线程间的数据竞争。
  • 线程上下文保存:线程局部存储也可用于保存当前执行线程的上下文信息,如用户身份验证信息、数据库连接等。

注意:

线程局部存储变量通常只能用于具有静态或线程存储期的变量,不能用于自动或动态分配的变量。使用线程局部存储时需要谨慎管理内存,避免内存泄漏或无效访问等问题。

线程的封装

线程的封装通常指的是将线程的创建、执行、同步、资源管理等逻辑封装到一个类或对象中,以便更好地组织代码,提高代码的可读性和可维护性

封装线程可以隐藏线程的复杂性,使得其他部分的代码可以更加简洁地与线程进行交互。

下面看具体代码:

Thread.hpp:对线程的封装

#ifndef __THREAD_HPP__
#define __THREAD_HPP__

#include<iostream>
#include<string>
#include<pthread.h>
#include<functional>
#include<unistd.h>

using namespace std;



namespace ThreadMdule
{
	//通过模板类可调用一切任何对象
    template<typename T>
    using func_t = std::function<void(T&)>;

    template<typename T>
    class Thread
    {
    public:
        void Excute()
        {
            _func(_data);
        }
        Thread(func_t<T> func, T data, const std::string &name="none-name")
            : _func(func), _data(data), _threadname(name), _stop(true)
        {}

        static void* threadroutine(void* args)
        {
            Thread<T>* self=static_cast<Thread<T>*>(args);
            self->Excute();
            return nullptr;
        }
        

        bool start()
        {
            int n=pthread_create(&_tid,nullptr,threadroutine,this);
            if(!n)
            {
                _stop = false;
                return true;
            }
            else
            {
                return false;
            }
        }
        void Detach()
        {
            if(!_stop)
            {
                pthread_detach(_tid);
            }
        }
        void Join()
        {
            if(!_stop)
            {
                pthread_join(_tid,nullptr);
            }
        }
        string name()
        {
            return _threadname;
        }
        void Stop()
        {
            _stop = true;
        }
        ~Thread() {}

    private:
        pthread_t _tid;
        std::string _threadname;
        T _data;  
        func_t<T> _func;
        bool _stop;
    };
}

#endif

线程类中包括了:线程名,数据,调用函数指针等;
通过start()函数来创建新线程:用到了函数threadroutinue,在函数中将函数成员_func(也就是具体函数的指针)使用了起来,就表示新线程的创建使用;

主函数的调用:

void print(int &cnt)
{
    while (cnt)
    {
        std::cout << "hello I am myself thread, cnt: " << cnt-- << std::endl;
        sleep(1);
    }
}

const int num=3;
int main()
{
    vector<Thread<int>> threads;
    //创建新线程
    for(int i=0;i<num;i++)
    {
        string name="thread"+to_string(i + 1);
        threads.emplace_back(print,3,name);
    }
    //启动进程
    for(auto& thread:threads)
    {
        thread.start();
    }

    //等待进程结束
    for(auto& thread:threads)
    {
        thread.Join();
        cout<<"wait thread done,thread is: "<<thread.name()<<endl;
    }

    return 0;
}

在这里插入图片描述
这样就是对线程的简单封装;

通过封装线程,我们可以更好地控制线程的创建、执行和销毁过程,同时使得代码更加清晰和易于维护。

此外,封装还可以帮助我们添加额外的功能,比如线程池的集成、异常处理、线程同步等。

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

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

相关文章

【喜报】科大睿智服务企业通过CMMI3级认证

​北京建投科信科技发展股份有限公司&#xff08;以下简称“北京建投科技” &#xff09;前身为北京银帝科技发展公司&#xff0c;成立于1993年&#xff0c;注册资本6,000万元&#xff0c;为中国建银投资有限责任公司&#xff08;简称“中国建投”&#xff09;的成员企业建投华…

ovs-vsctl错误:Port does not contain a column whoes name matches “--id“

出错的命令是: ovs-vsctl -- set Bridge br-int mirrors=@m -- --id=@snooper0 get Port snooper0\ -- --id=@patch-tun get Port patch-tun -- --id=@m create Mirror name=mymirror \ select

微软Edge浏览器深度解析:功能、同步、隐私与安全

微软Edge浏览器是微软公司开发的一款网页浏览器,它基于Chromium内核,提供了快速、安全和兼容性良好的网页浏览体验。以下是关于微软Edge浏览器的详细信息和使用指南: 微软Edge浏览器的主要特点: 1. 基于Chromium内核: 渲染引擎:Chromium内核是基于开源项目Blink的,它…

LNMP分布式搭建

一、准备三台主机 192.168.100.11 mysql 192.168.100.12 nginx 192.168.100.13 php 二、关闭防火墙及安全策略 systemctl stop firewalld setenforce 0 三、安装nginx&#xff08;192.168.100.11&#xff09; 1、添加nginx源 vim /etc/yum.repos.d/ng…

数据整理的Compact流程 (二)|OceanBase数据转储合并技术解读(二)

上篇文章《数据整理的Compact流程 &#xff08;一&#xff09;&#xff5c;OceanBase数据转储合并技术解读&#xff08;二&#xff09;》中&#xff0c;有讲解到&#xff0c;在OceanBase数据库中&#xff0c;当MemTable写满时&#xff0c;将其下刷到Mini SSTable的过程包含两个…

正邦科技(day4)

烧录 一、烧录固件二、 通讯模块升级1&#xff1a;USB的方式升级固件2&#xff1a;通过mqtt的方式升级固件3&#xff1a;切换环境 三、 烧录WiFi1&#xff1a;短接2&#xff1a;烧录脚本 设备注意事项&#xff1a; 第一种方式&#xff1a;通信模组和MCU都可以统一烧录BoodLoade…

数据结构---栈队列

栈和队列是我们数据结构中经常使用的数据结构&#xff0c;所以现在来了解一下栈和队列。 栈 特点&#xff1a; 栈是一种特殊的线性表&#xff0c;其中进行数据插入和弹出的部分叫做栈顶&#xff0c;另一端叫做栈底。 只允许数据从栈顶压入&#xff0c;从栈顶弹出即先进后出的…

Mac | Mac M 芯片应用意外退出问题

现象问题 电脑配置&#xff1a;MacBook Pro M1&#xff0c;系统 Sonoma 很多小伙伴新买了 M 芯片的 MacBook&#xff0c;在下载下应用后进行安装&#xff0c;安装成功后却无法打开&#xff0c;提示意外退出。报错如图 原因 部分应用过适配了 M 芯片&#xff0c;但还是有些应…

Windows配置共享文件夹

正文共&#xff1a;888 字 16 图&#xff0c;预估阅读时间&#xff1a;1 分钟 我们前面介绍了如果安装NAS工具&#xff08;废物利用&#xff0c;矿渣装个黑群晖。家庭小NAS搞起来&#xff01;&#xff09;&#xff0c;也介绍过如果配置远程桌面的多账号登录&#xff08;Windows…

Apache Nemo: A Framework for Optimizing Distributed Data Processing——论文泛读

TOCS 2021 Paper 论文阅读笔记整理 问题 针对资源和数据特性优化分布式数据处理的调度和通信&#xff0c;对于实现高性能至关重要。在最近的研究中广泛讨论的例子是&#xff1a;地理分布的资源[14&#xff0c;30&#xff0c;47&#xff0c;48]、廉价的瞬时资源[34&#xff0c…

五分钟“手撕”链表

为了提高大家的学习效率&#xff0c;我把代码放开头&#xff0c;供查阅。 目录 一、链表的实现代码 二、什么是链表 三、链表的分类 四、链表的常见操作 插入 删除 五、Java自带的LinkedList 两个构造方法 一些常用方法 六、LinkedList的遍历 七、ArrayList和Linke…

基恩士PLC与ModbusTCP转Profibus网关实现与激光设备的高效连接

本文将探讨如何通过使用基恩士PLC以及无锡耐特森ModbusTCP转Profibus网关来实现与激光设备的高效连接。在当今工业自动化领域&#xff0c;不同厂商的硬件设备和软件系统之间的互联互通性成为了提高生产效率、实现智能制造的关键因素。其中&#xff0c;可编程逻辑控制器&#xf…

spring boot 3.x版本 引入 swagger2启动时报错

一&#xff0c;问题 Spring Boot 3.x版本的项目里&#xff0c;准备引入Swagger2作为接口文档&#xff0c;但是项目启动报错&#xff1a; java.lang.TypeNotPresentException: Type javax.servlet.http.HttpServletRequest not present at java.base/sun.reflect.generics.…

高等教育的AI革新:OpenAI面向大学推出ChatGPT Edu

OpenAI推出了ChatGPT Edu&#xff0c;这是一个为大学设计的专用版本&#xff0c;旨在让学生、教职员工、研究人员和校园运营能够负责任地使用AI。 ChatGPT Edu 将AI技术引入了教育领域&#xff0c;其建立在GPT-4o的基础上&#xff0c;它不仅能够处理文本和图像&#xff0c;还…

【linux深入剖析】进程间通信

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1.进程间通信目的2. 什么…

dubbo复习:(17)dubbo连接skywalking

一、准备skywalking 8.7.0并启动 二、配置好skywalking agent 三、服务提供者端的依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema…

结构体中内存的对齐

前言 学C的同学应该知道~ 想精通C语言就不得不面对—指针与内存 续上次指针进阶&#xff0c;这一章我来聊一聊C语言内存对齐的问题 学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的&#x1f601; 思考 #include<stdio.h> typedef struct s1 {char a;char …

Firebase Local Emulator Suite详解

文章目录 Firebase Local Emulator Suite 组件安装和使用步骤1. 安装 Firebase CLI2. 初始化 Firebase 项目3. 配置模拟器4. 启动模拟器5. 配置应用程序使用本地模拟器 常见用途 Firebase Local Emulator Suite 是一组本地服务&#xff0c;可以模拟 Firebase 平台的在线服务&am…

抖音电商“山货上头条”走进广东茂名,助销白糖罂荔枝地标农产品

受异常天气影响&#xff0c;今年广西、广东等地“桂味”和“香荔”等荔枝品种罕见减产。入夏以来&#xff0c;“痛失荔枝自由”“荔枝价格暴涨”等话题频上热搜。 为帮助消费者尝到品质良好、价格实惠的新鲜荔枝&#xff0c;今年“抖音商城618好物节”活动期间&#xff0c;抖音…

优化CPU占用率及内存占用2

在标准化无线通信板时&#xff0c;关注过程序占用ram的问题&#xff0c;当时 发现每一个线程都会分配8M栈空间&#xff0c;这次换rk3568后&#xff0c;偶尔看了下RAM占用&#xff0c;吓了一跳&#xff0c;不但每个线程有8M栈空间&#xff0c;几乎每个线程都占用了64MB的一个RAM…