Linux基础内容(25)—— 线程控制和线程结构

news2024/11/28 18:52:13

Linux基础内容(24) —— 线程概念_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/131294692?spm=1001.2014.3001.5501

目录

1.线程操作

1.线程创建问题

2.线程终止问题

1.exit退出

2.pthread_exit退出

 3.直接退出

3.线程等待问题

信号问题

4.线程取消

5.线程分离

2.理解线程库

重新认识线程库

1.语言层面

2.结构设计

3.pthread_id的含义


1.线程操作

1.线程创建问题

class ThreadData
{
public:
    pthread_t tid;
    char namebuffer[64];
};

void *start_routine(void *args)
{
    ThreadData *td = static_cast<ThreadData *>(args); // 安全的强制类型转换
    int cnt = 10;
    while (cnt)
    {
        cout << "new thread success, name: " << td->namebuffer << " cnt: " << cnt << endl;
        sleep(1);
    }
    delete td;
    return nullptr;
}

int main()
{
    vector<ThreadData*> tids;
#define NUM 10
    for (int i = 0; i < NUM; i++)
    {
        ThreadData *td = new ThreadData();
        snprintf(td->namebuffer, sizeof(td->namebuffer), "%s:%d", "thread", i);
        pthread_create(&td->tid, nullptr, start_routine, (void *)td);
        tids.push_back(td);
    }
    while (true)
    {
        cout << "new thread success, name: main thread" << endl;
        sleep(1);
    }
    return 0;
}

1.我们创造了10个线程同时进入同一个函数,该函数为可重入状态。start_routine就是可重入函数

2.此时的函数是可重入函数,因为没有出现问题。这些cnt都是临时变量,在各自的线程之中,不会互现影响,也反映了线程有自己的独立栈结构

3.循环式的创造线程不能直接循环,这样可能内部的缓冲区没有被修改,线程就创造了一堆,使得每一个线程的信息都一样

2.线程终止问题

1.exit退出

由于线程的健壮性问题,我们在任意一个执行流中调用ecit函数,都会使得整个进程退出。因为exit针对的对象为进程,我们的信号发送给进程后,自然进程结束,线程也跟着结束。

2.pthread_exit退出

 3.直接退出

如果线程执行结束,直接在函数中return。操作系统会自动回收线程

3.线程等待问题

其实线程跟进程一样都需要在结束后等待操作系统回收。如果不等待,线程对应的PCB也没有被释放,那么就会出现类似于进程的僵尸进程的内存漏泄问题。不过可以回收线程释放的信息,只释放线程。

void *start_routine(void *args)
{
    ThreadData *td = static_cast<ThreadData *>(args); // 安全的强制类型转换
    int cnt = 10;
    while (cnt)
    {
        cout << "new thread success, name: " << td->namebuffer << " cnt: " << cnt << endl;
        sleep(1);
    }
    //delete td;
    return nullptr;
}

for(auto &iter : threads)
{
    int n = pthread_join(iter->tid, nullptr);
    assert(n == 0);
    cout << "join : " << iter->namebuffer << " success " << endl;
    delete iter;
}

//注意为了让已经释放空间的线程能打出其对应的名字,我们需要把start_routine中delete td进行删除
//因为我们不想要早其打印之前就被销毁,那么只能在其打印后进行释放

 对指定的thread进行等待,viod**为二级指针是线程的返回的参数。

其实线程join等待回收能将线程exit的数据进行回收

class ThreadData
{
public:
    int number;
    pthread_t tid;
    char namebuffer[64];
};

void *start_routine(void *args)
{
    ThreadData *td = static_cast<ThreadData *>(args); // 安全的强制类型转换
    int cnt = 10;
    while (cnt)
    {
        cout << "new thread success, name: " << td->namebuffer << " cnt: " << cnt << endl;
        sleep(1);
        // int *p = nullptr;
        //  p=NULL;
        //*p=0;
    }
    //delete td;
    return (void*)td->number;
}

    for(auto &iter : threads)
    {
        void* ret=nullptr;
        int n = pthread_join(iter->tid, &ret);
        assert(n == 0);
        cout << "join : " << iter->namebuffer << " success, number: " <<(int_least32_t)ret<< endl;
        delete iter;
    }

 这样就能接受到信息了。当然我们也可以返回一个结构体,这样调回来的就是结构体的信息了。

信号问题

线程出问题,不会收到信号,因为如果线程挂了,进程都退出了。那么也就意味着join等待不会考虑信号的问题。

4.线程取消

线程能被其他线程取消

5.线程分离

1.线程的等待功能只有阻塞等待

2.如果线程释放时,我们需要看到线程的返回信息,那么join的函数就可以实现我们需要的

3.如果我们不想要线程的信息,也就意味着join的回收信号是无意义的

4.那么我们不能像进程那样非阻塞等待,是否可以像线程类似通过信号进行自动回收,答案是肯定的,线程分离就能将线程自动被操作系统回收

pthread_self:哪个线程调用,就得到哪个线程的pthread_t

std::string changeId(const pthread_t& pthread_id)
{
    char tid[128];
    snprintf(tid,sizeof(tid),"0x%x",pthread_id);
    return tid;
}

void *start_routine(void *args)
{
    std::string threadname = static_cast<const char *>(args); // 安全的强制类型转换
    while (true)
    {
        std::cout << threadname << " running ...: " << changeId(pthread_self()) << std::endl;
        sleep(1);
    }
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, nullptr, start_routine, (void *)"thread 1");
    std::string main_id=changeId(pthread_self());

    std::cout << "main thread running ...: " << changeId(tid) << std::endl;
    pthread_join(tid, nullptr);
    return 0;
}

两个地址完全一致,说明知道指向的线程地址是多少

pthread_detach:分离一个指定的线程

 

2.理解线程库

1.重新认识线程库

1.语言层面

mypthread:mypthread.cc
	g++ -o $@ $^ -std=c++11

.PHONY:clean
clean:
	rm -f mypthread
#include <iostream>
#include <unistd.h>
#include <thread>

void thread_run()
{
    while (true)
    {
        std::cout << "我是新线程..." << std::endl;
        sleep(1);
    }
}

int main()
{
    std::thread t1(thread_run);
    while (true)
    {
        std::cout << "我是主线程..." << std::endl;
        sleep(1);
    }
    t1.join();
    return 0;
}

若这样,编译器编不过,系统提示我们没有包含pthread库

1.C++11的多线程在linux的环境中其实是对pthread库的封装,也就意味着,c++创造的线程在linux下依然是轻量级进程

2.不管是什么语言,在linux的环境下都会调用pthread库。

2.结构设计

1.linux没有真正意义上的线程,只有轻量级进程。也就意味着linux提供的调用函数为轻量级进程

2.但是作为用户不会考虑linux的环境和设计,需要的是线程

3.pthread库提供的线程库就是调用linux对轻量级进程的调用函数的封装。那么也就是说其实我们使用的线程其实是库提供给我们的

4.既然库提供给我们对于的结构了,那么我们使用时一定是被管理的。那么库给我们提供的pthread就有其属性,以至于用来记录所有线程的信息

5.pthread_attr_t就是存储线程属性的结构联合体,线程的属性比进程的属性要少。

6.上面的设计其实就是用户及线程,即用户关心的线程属性在库中,内存提供了线程的函数会调用

7.用户级线程与内核轻量级进程一一对应,达到管理的作用

3.pthread_id的含义

1.在虚拟内存地址中,对应的栈就是主线程的栈

2.线程库其实就是磁盘的文件,它在被调用后会在虚拟内存的共享区中出现

3.共享区中存储着线程结构体的地址,而多个线程则是通过数组的形式排列存储在虚拟空间

4.共享区指向动态库找到映射的线程,线程中存储有局部存储和独立栈

5.那么我们就能进一步理解所谓的线程库就是封装了linux中的clone轻量级进程

6.增加__thread在内置类型全局变量前,会使得内置类型转换为线程的局部存储中,每一个线程都来一份

__thread int cnt = 0;

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

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

相关文章

只需一个提示词解除GPT-4的字符限制!

ChatGPT的内存有限,GPT-3.5-turbo的限制为4897个令牌,而GPT-4的最大限制为8192。如果您在使用GPT-4进行聊天时超过8192个令牌(约6827个单词),它就会开始遗忘。我想出了一种新的技巧,可以轻松将对话扩展10倍。 这种技巧不会将对话中的每个字都保存到内存中。当您去开会时,会有人…

0502事务原理-InnoDB引擎-MySQL-数据库

1 概述 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff0c;事务会把所有操作作为一个整体一起向系统提交或者撤销操作请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失败。 事务特性 原子性&#xff08;Atomatic&#xff09;&#xff1a;事…

MiniGPT4系列之一部署篇:在RTX-3090 Ubuntu服务器部署步骤详解

MiniGPT4系列之一部署篇&#xff1a;在RTX-3090 Ubuntu服务器部署步骤详解_seaside2003的博客-CSDN博客 MiniGPT4系列之二推理篇命令行方式&#xff1a;在RTX-3090 Ubuntu服务器推理详解_seaside2003的博客-CSDN博客 MiniGPT4系列之三模型推理 (Web UI)&#xff1a;在RTX-309…

外包软件定制开发中关于沟通障碍及对应解决方案

引言 外包软件定制开发在当今的商业环境中越来越常见。它为公司提供了许多好处&#xff0c;包括降低成本、加速交付和专注于核心业务。然而&#xff0c;沟通障碍常常是外包软件定制开发中的一个重要挑战。由于外包团队和客户位于不同的地理位置、文化和语言差异&#xff0c;沟…

Python 列表 sort()函数使用详解

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 sort函数使用详解 1、升序降序2、sort()和sorted()的区别3、切片排序4、指定排序…

【C++】设计模式-单例模式

目录 一、单例模式 单例模式的三个要点 针对上述三要点的解决方案 常用的两类单例模式 二、懒汉模式实现 1.基本实现 2.锁静态成员析构单例 3.双层检查锁定优化 4.双层检查锁定智能指针 三、饿汉模式实现 1.基础实现 2.嵌套内部类解决内存泄漏 3.智能指针解决内存泄…

一种用于RBF神经网络的新型自适应内核研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

vuejs源码之虚拟dom中的vnode

在虚拟dom中&#xff0c;vnode是比较重要的。 什么是vnode 在vuejs中&#xff0c;有一个Vnode类 使用它可以实例不同类型的vnode实例&#xff0c;而不同类型的vnode实例各自表示不同类型的dom元素。 例如dom元素有文本节点&#xff0c;元素节点&#xff0c;注释节点等。 co…

Spring IoC及DI依赖注入

Spring 1.Spring的含义&#xff1a; Spring 可从狭义与广义两个角度看待 狭义的 Spring 是指 Spring 框架(Spring Fremework) 广义的 Spring 是指 Spring 生态体系 2.狭义的 Spring 框架 Spring 框架是企业开发复杂性的一站式解决方案 Spring 框架的核心是 IoC 容器和 AO…

数据库java中jdbcTemplate的事务问题

1.什么都不设置事务是默认提交的 两次获取的连接是不是一样的 参考文献(重磅): (542条消息) JdbcTemplate的事务控制_jdbctemplate transactionmanager_DayDayUp丶的博客-CSDN博客 PostMapping("/pinYin22")CrossOriginTransactionalpublic String pinYin22(HttpS…

【js实现语言国际化】使用json配置文件实现

需求&#xff1a;使用js让项目实现中文简体、繁体跟英文的切换&#xff0c;实现语言国际化 首先准备三种json配置文件&#xff1a; en.json {"textOne": "Today is Monday","textTwo": "Tomorrow is Tuesday","textThree"…

F#奇妙游(14):F#实现WPF的绑定

WPF中的绑定 绑定在UI开发中是一个非常重要的概念&#xff0c;它可以让我们的UI界面和数据模型之间建立起联系&#xff0c;当数据模型发生变化时&#xff0c;UI界面也会随之变化&#xff0c;反之亦然。这样的好处是显而易见的&#xff0c;我们不需要手动去更新UI界面&#xff…

金智教育IPO过会:计划募资约6亿元,郭超、史鸣杰为实控人

7月13日&#xff0c;深圳证券交易所披露的信息显示&#xff0c;江苏金智教育信息股份有限公司&#xff08;下称“金智教育”&#xff09;获得上市委会议通过。据贝多财经了解&#xff0c;金智教育于2022年6月30日递交上市申请材料&#xff0c;先后递交了6个版本的招股书&#x…

NDK OpenGL与OpenCV实现大眼萌特效

NDK​系列之OpenGL与OpenCV实现大眼萌特效&#xff0c;本节主要是在上一节OpenGL仿抖音极快极慢录制特效视频上增加大眼萌的特效。 OpenGL视频特效系列&#xff1a; NDK OpenGL渲染画面效果 NDK OpenGL离屏渲染与工程代码整合 NDK OpenGL仿抖音极快极慢录制特效视频 NDK O…

通讯录实现

普通版 需求 通讯录可以用来存储1000个人的信息&#xff0c;每个人的信息包括&#xff1a;姓名、性别、年龄、电话、住址 提供方法&#xff1a; 添加联系人信息删除指定联系人信息查找指定联系人信息修改指定联系人信息显示所有联系人信息清空所有联系人以名字排序所有联系…

【Linux后端服务器开发】UDP协议

目录 一、端口号 二、UDP报头格式 三、UDP的特点 四、UDP协议实现网络聊天群 一、端口号 端口号port标识了一个主机上进行通信的不同的应用程序。 0 ~ 1023&#xff1a;系统端口号&#xff0c;HTTP、FTP、SSH等这些广为使用的应用层协议&#xff0c;它们的端口号都是固定…

Windows软件开发常用技巧总结

本文总结了本人在日常工作学习中遇到的问题及其解决方法&#xff0c;没有固定的涉及领域 目的就是为了在下一次遇到类似问题的时候方便查找&#xff0c;从而快速解决问题 本文不定时更新~ 目录 Windows使用 如何实现桌面图标随意排列 文件资源管理器相关 显示隐藏文件 修改…

Linux--获取最近一次的进程退出码:echo $?

举例&#xff1a; #include <stdio.h> int main() { printf("hello world,pid: %d,ppid: %…

JavaFx 用户界面控件3——TableView

1.表格视图 TableView ableView是JavaFX提供的一个强大的控件&#xff0c;可以用于显示表格数据。它通过为TableView设定items属性&#xff08;存储行数据的ObservableList对象&#xff09;和列属性&#xff08;TableColumn对象&#xff09;来完成数据填充与展示。 以下是一个…

如何做一线leader

文章目录 道领导力五个层次关键&#xff1a;信任 处事原则 术避坑指南事急则乱员工沟通向上管理人才招聘人才培养裁人员工关怀 道 领导力 五个层次 职位 当面交代事情&#xff0c;观察眼神、语气。反复确认有没有问题&#xff0c;如果有可以及时讨论策略&#xff0c;准备资源…