【Linux多线程】详解线程控制、线程分离

news2024/11/16 7:51:16

00

线程互斥与同步

  • 👸 理解线程
    • 🤴pthead_t
    • 🥷关于线程
    • 🦸‍♀️线程控制
      • POSIX线程库
      • 线程ID及进程地址空间布局
  • 🦸线程分离
    • __thread关键字
    • 🦸‍♂️pthread_detach函数
    • 🦹‍♀️pthread_exit函数
    • 🦹 exit和pthread_exit

👸 理解线程

🤴pthead_t

pthread_t 是 POSIX 线程库中的数据类型,用于表示线程标识符。POSIX(Portable Operating System Interface for Unix)是一套标准,定义了在 UNIX 系统中的应用程序编程接口(API)规范,其中包含了线程操作的标准接口。

在多线程编程中,每个线程都有一个唯一的标识符,用于区分不同的线程。pthread_t 就是用来存储这个线程标识符的数据类型。它在 <pthread.h> 头文件中定义。

在使用 POSIX 线程库创建线程时,会得到一个 pthread_t 类型的变量,用于标识新创建的线程。您可以使用 pthread_t 变量来操作、控制或等待特定的线程。通常情况下,我们通过调用 pthread_create 函数来创建新线程,并将新线程的标识符保存在 pthread_t 变量中。

🥷关于线程

关于线程我们要知道以下概念

  1. 线程是一个独立的执行流
  2. 线程一定会在自己的执行过程中产生临时数据(调用函数,定义局部变量等等)
  3. 线程一定有自己的独立栈结构

🦸‍♀️线程控制

POSIX线程库

  1. 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”打头的
  2. 要使用这些函数库,要通过引入头文<pthread.h>
  3. 链接这些线程函数库时要使用编译器命令的“-lpthread”选项
  • 创建

功能:创建一个新的线程
原型
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *
(start_routine)(void), void *arg);
参数
thread:返回线程ID
attr:设置线程的属性,attr为NULL表示使用默认属性
start_routine:是个函数地址,线程启动后要执行的函数
arg:传给线程启动函数的参数
返回值:成功返回0;失败返回错误码

  • 错误检查:

传统的一些函数是,成功返回0,失败返回-1,并且对全局变量errno赋值以指示错误。
pthreads函数出错时不会设置全局变量errno(而大部分其他POSIX函数会这样做)。而是将错误代码通
过返回值返回
pthreads同样也提供了线程内的errno变量,以支持其它使用errno的代码。对于pthreads函数的错误,
建议通过返回值业判定,因为读取返回值要比读取线程内的errno变量的开销更小

线程ID及进程地址空间布局

pthread_ create函数会产生一个线程ID,存放在第一个参数指向的地址中。该线程ID和前面说的线程ID不是一回事。
前面讲的线程ID属于进程调度的范畴。因为线程是轻量级进程,是操作系统调度器的最小单位,所以需要
一个数值来唯一表示该线程。
pthread_ create函数第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,
属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。
线程库NPTL提供了pthread_ self函数,可以获得线程自身的ID:
pthread_t pthread_self(void);

pthread_t 到底是什么类型呢?取决于实现。对于Linux目前实现的NPTL实现而言,pthread_t类型的线程ID,本质就是一个进程地址空间上的一个地址。

🦸线程分离

  • 代码
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include<iostream>
using namespace std;
  int N=1000;
void* threadF1(void *argv)
{
    while (true)
    {
        cout<<"thread:"<<pthread_self()<<"   "<<"N的值:"<<N<<"   "<<"&N:"<<"   "<<&N<<"Inc:"<<N++<<endl;
        sleep(1);
    }
}
int main()
{
    pthread_t td1;
    pthread_t td2;
    pthread_t td3;
    pthread_create(&td1,nullptr,threadF1,(void*)"td1");
    pthread_create(&td2,nullptr,threadF1,(void*)"td2");
    pthread_create(&td3,nullptr,threadF1,(void*)"td3");

    pthread_join(td1,nullptr);
    pthread_join(td2,nullptr);
    pthread_join(td3,nullptr);




    return 0;
}
  • 结果
    00
    总结起来就是 共享的资源N 在进行++操作的时候 多个线程访问的是同一个N 那么怎么让线程分离呢?

__thread关键字

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include<iostream>
#include <sys/syscall.h>
using namespace std;
  __thread int global_value=1000;
void* threadF1(void *argv)
{
    while (true)
    {
       cout << "thread " << pthread_self() << " global_value: "
            << global_value << " &global_value: " << &global_value
              << " Inc: " << global_value++ << " lwp: " << ::syscall(SYS_gettid)<<endl;
         sleep(1);
      // mak   break;
    }
}
int main()
{
    pthread_t td1;
    pthread_t td2;
    pthread_t td3;
    pthread_create(&td1,nullptr,threadF1,(void*)"td1");
    pthread_create(&td2,nullptr,threadF1,(void*)"td2");
    pthread_create(&td3,nullptr,threadF1,(void*)"td3");

    pthread_join(td1,nullptr);
    pthread_join(td2,nullptr);
    pthread_join(td3,nullptr);




    return 0;
}

看把共享数据块global_value用 __thread修饰即可 !

  • 结果:
    00

🦸‍♂️pthread_detach函数

pthread_detach 函数用于将一个线程标记为“可分离”的状态。当一个线程被标记为“可分离”,则在该线程终止时,线程的资源会自动释放,而无需其他线程调用 pthread_join 来等待和回收该线程的资源。

具体来说,pthread_detach 函数用于向线程库指示,当目标线程(被调用 pthread_detach 的线程)终止时,其状态和资源可以被系统回收,而不需要其他线程调用 pthread_join 来等待其终止。

使用 pthread_detach 的好处是,它可以防止资源泄漏。如果不使用 pthread_detach,当一个线程终止时,它的资源将一直保留在系统中,直到其他线程调用 pthread_join 来回收它的资源。如果没有及时回收资源,可能会导致资源泄漏。

在实际应用中,通常将不需要回收线程资源的线程标记为“可分离”,而将需要回收资源的线程标记为“非分离”。标记线程为“非分离”后,其他线程可以使用 pthread_join 来等待它的终止,并回收其资源。

要使用 pthread_detach,只需在目标线程中调用它即可,例如

#include <pthread.h>
#include <stdio.h>

void* threadFunction(void* arg) {
    // Thread logic
    printf("Thread function executed.\n");
    return NULL;
}

int main() {
    pthread_t thread;
    if (pthread_create(&thread, NULL, threadFunction, NULL) != 0) {
        perror("pthread_create");
        return 1;
    }

    // Mark the thread as detachable
    if (pthread_detach(thread) != 0) {
        perror("pthread_detach");
        return 1;
    }

    // Continue with other tasks, no need to call pthread_join.

    // Sleep to give the thread time to execute before the program exits
    sleep(1);
    return 0;
}

在上述示例中,pthread_detach 函数被调用,将线程 thread 标记为“可分离”的状态。因此,我们不需要在主线程中调用 pthread_join 来回收线程资源。在主线程中可以继续进行其他任务,线程 thread 的资源会在它终止时自动释放

🦹‍♀️pthread_exit函数

pthread_exit 函数用于在线程内部终止当前线程的执行,并返回一个指定的退出值。这个函数允许线程在任何地方终止,而不必等待线程的函数返回。

函数原型:

#include <pthread.h>

void pthread_exit(void *retval);

参数 retval 是一个指向任意类型的指针,它表示线程的退出值。这个值可以被其他线程通过 pthread_join 函数获取到。

当一个线程调用 pthread_exit 函数时,它会立即终止当前线程的执行,并将 retval 指向的值传递给等待它的线程。

pthread_exit 的使用场景包括:

在线程执行完任务后,通过 pthread_exit 终止线程,而不是返回到线程的创建点。
在线程内部发现错误或条件,需要立即终止线程的执行。
在线程执行过程中遇到某种情况需要立即退出,并向其他线程传递一些信息。
以下是一个简单的示例,演示了 pthread_exit 的使用:

#include <pthread.h>
#include <stdio.h>

void* threadFunction(void* arg) {
    // Thread logic
    printf("Thread function executed.\n");

    int exitValue = 42;
    pthread_exit((void*) &exitValue);
}

int main() {
    pthread_t thread;
    if (pthread_create(&thread, NULL, threadFunction, NULL) != 0) {
        perror("pthread_create");
        return 1;
    }

    void* returnValue;
    if (pthread_join(thread, &returnValue) != 0) {
        perror("pthread_join");
        return 1;
    }

    // Cast the return value back to its original type
    int exitValue = *(int*) returnValue;
    printf("Thread exit value: %d\n", exitValue);

    return 0;
}

在上述示例中,线程函数 threadFunction 调用 pthread_exit 来终止线程的执行,并传递了一个整数值作为退出值。主线程通过 pthread_join 来等待线程的结束,并获取线程的退出值,然后打印出来

🦹 exit和pthread_exit

pthread_exit 和 exit 都可以用于终止程序的执行,但它们之间有几个关键的区别:

作用范围:

pthread_exit 仅用于终止调用它的线程的执行,不会终止整个进程。
exit 会立即终止整个进程的执行,包括所有线程。
参数传递:

pthread_exit 允许在线程内部传递一个指向任意类型的指针作为退出值,其他线程可以通过 pthread_join 来获取这个退出值。
exit 的退出值必须是整数类型,它会作为进程的退出状态传递给操作系统。
资源回收:

pthread_exit 不会自动释放线程占用的资源,因此需要在适当的地方手动释放资源。
exit 会自动释放整个进程占用的资源,包括打开的文件、动态分配的内存等。
使用场景:

pthread_exit 通常用于线程内部,在线程完成任务后主动退出,或者在线程内部遇到错误时终止线程的执行。
exit 通常用于整个程序,在程序完成主要任务后终止整个进程的执行,一般在 main 函数的末尾或者需要提前退出程序的地方使用。
注意:在多线程程序中,使用 exit 可能会导致一些问题,因为它会立即终止整个进程,可能会导致其他线程的资源无法正确释放,从而造成资源泄漏或未定义行为。在多线程程序中,推荐使用 pthread_exit 来终止线程的执行,以保证资源的正确释放。
00

🦹‍♂️ 🤶 🧑‍🎄 🎅 🧙‍♀️ 🧙 🧙‍♂️ 🧝‍♀️ 🧝 🧝‍♂️ 🧛‍♀️ 🧛 🧛‍♂️ 🧟‍♀️ 🧟 🧟‍♂️ 🧞‍♀️ 🧞 🧞‍♂️ 🧜‍♀️ 🧜 🧜‍♂️ 🧚‍♀️ 🧚 🧚‍♂️ 👼

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

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

相关文章

[JavaWeb]SQL介绍-DDL-DML

SQL介绍-DDL-DML 一.SQL简介1.简介2.SQL通用语法3.SQL语言的分类 二.DDL-操作数据库与表1.DDL操作数据库2.DDL操作表①.查询表(Retrieve)②.创建表(Create)③.修改表(Update)④.删除表(Delete) 三.Navicat的安装与使用四.DML-操作表数据1.添加(Insert)2.修改(Update)3.删除(Del…

【C++】反向迭代器的模拟实现通用(可运用于vector,string,list等模拟容器)

文章目录 前言一、反向迭代器封装&#xff08;reverseiterator&#xff09;1.构造函数1解引用操作.3.->运算符重载4.前置&#xff0c;后置5.前置--&#xff0c;后置--6.不等号运算符重载7.完整代码 二、rbegin&#xff08;&#xff09;以及rend&#xff08;&#xff09;1.rb…

[nlp] TF-IDF算法介绍

&#xff08;1&#xff09;TF是词频(Term Frequency) 词频是文档中词出现的概率。 &#xff08;2&#xff09; IDF是逆向文件频率(Inverse Document Frequency) 包含词条的文档越少&#xff0c;IDF越大。

01-导数的定义_左导数和右导数

微积分 导数的定义 左导数与右导数、可导函数 趋近于 0 有两个方向&#xff0c;从左边趋向于 0 是左导数&#xff0c;反之是右导数 下面的绝对值函数的左导数和右导数不相同&#xff0c;一个-1 一个1&#xff0c;0 位置不可导 f(x)|x|&#xff0c; 导数可以理解为某点的斜率…

生命在于学习——指纹混淆技术学习

一、前言 本篇文章仅为学习笔记记录&#xff0c;不得用于违规用途。 本篇文章为安全社公众号的Poker安全所发&#xff0c;本文仅为学习复现。 二、介绍 指纹混淆技术&#xff0c;顾名思义&#xff0c;就是迷惑指纹扫描识别技术。 三、思路 作者的思路&#xff1a; 1、伪…

代码随香录day31

今天开始贪心算法了&#xff01; 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 贪心算法一般分为如下四步&#xff1a; 将问题分解为若干个子问题找出适合的贪心策略求解每一个子问题的最优解将局部最优解堆叠成全局最优解 455. 分发饼干 这里的思路…

openEuler?搭建java开发环境的详细过程

目录 1. 初始化环境2. 安装jdk83. 安装SVN4. 安装Git5. 安装Node.js6. 下载并激活IntelliJ IDEA7. 下载并激活Navicat 本文操作系统及版本号&#xff1a;↓ openEuler release 22.03 LTS Linux version 5.10.0-60.35.0.64.oe2203.x86 _64 1. 初始化环境 ? 1 2 3 4 # 1. 更新…

Spring事务的传播机制与隔离级别

目录 前言事务的隔离级别事务特性Spring 中设置事务隔离级别MySQL的隔离级别Spring中的隔离级别 Spring的传播机制事务传播机制是什么&#xff1f;为什么需要事务传播机制&#xff1f;事务传播机制有哪些&#xff1f; 事务的隔离级别 与 传播机制 解决的问题 前言 无论对于那个…

2020年全国硕士研究生入学统一考试管理类专业学位联考写作试题——解析版

四、写作第56~57小题&#xff0c;共65分。其中论证有效性分析30分&#xff0c;论说文35分。 56. 论证有效性分析&#xff1a;分析下述论证中存在的缺陷和漏洞&#xff0c;选择若干要点&#xff0c;写一篇600字左右的文章&#xff0c;对该论证的有效性进行分析和评论。( 论证有…

自动装配再次理解

随便点进去一个自动装配类&#xff0c;也就是spring.factories 文件下的一个全限定名指定的一个配置类 里面有个内部类 Encoding 类 这个注解是绑定了yaml文件&#xff0c;通过前缀可以往里面赋值&#xff0c;来实现自定义配置Springboot 了解完自动装配的原理后&#xff0c;我…

<C语言> 预处理和宏

1.预定义符号 __FILE__ //进行编译的源文件 __LINE__ //文件当前的行号 __DATE__ //文件被编译的日期 __TIME__ //文件被编译的时间 __STDC__ //如果编译器遵循ANSI C&#xff0c;其值为1&#xff0c;否则未定义这些预定义符号都是C语言内置的。 举个例子&…

如何高效维护电脑

电脑维护技巧&#xff1a;让你的电脑始终高效稳定 电脑维护技巧&#xff1a;让你的电脑始终高效稳定引言方向一&#xff1a;介绍你的电脑方向二&#xff1a;介绍一下你的日常维护措施方向三&#xff1a;给出一些你觉得有用的维护技巧方向四&#xff1a;其他你想补充的方向五&am…

苍穹外卖学习心得与总结【对比瑞吉】【如何获得铁粉】

对于苍穹外卖项目&#xff0c;从学习课程加复习已经13天了。 对于一名已经学习过SSMLinuxRedis数据库的Java练习生来说&#xff0c;这个项目相对于之前学习的《瑞吉外卖》新增了很多功能和技术&#xff0c;是很值得练手和提升的课程&#xff0c;下面给出自己的一些见解。&#…

【点云处理教程】02从 Python 中的深度图像估计点云

一、说明 这是“点云处理”教程的第二篇文章。“点云处理”教程对初学者友好&#xff0c;我们将在其中简单地介绍从数据准备到数据分割和分类的点云处理管道。在本教程中&#xff0c;我们将学习如何在不使用 Open3D 库的情况下从深度图像计算点云。我们还将展示如何优化代码以获…

调整数组顺序使奇数位于偶数前面——剑指 Offer 21

文章目录 题目描述法一 两次遍历法二 双指针一次遍历法三 原地交换 题目描述 法一 两次遍历 class Solution{ public:vectro<int> exchange(vector<int>& nums){vector<int> res;for(auto & num : nums){if(num%21){res.push_back(num);}}for(auto &…

Java常用API:StringBuilder、StringBuffer、StringJoiner

StringBuilder的几个常用的API StringBuilder s new StringBuilder("111");//111 //1.拼接内容 s.append(12); s.append("11"); s.append(true);//2.支持链式编程 s.append(12).append("11").append(true);//输出是1211true //3.反转操作 s.reve…

c++[左值+右值](25)

左值 对左值取别名 左值举例 int main() {//左值&#xff1a;可以取地址int a 10;const int b 20;int* p &a; //a&#xff0c;b&#xff0c;p均是左值*p 100; //*p也是左值return 0; }左值引用举例 int main() {//以下 p、b、c、*p都是…

《向量数据库指南》:向量数据库Pinecone如何集成Elasticsearch

目录 上传嵌入模型 上传数据集 创建嵌入 将Elasticsearch索引移动到Pinecone 概要 是一个强大的开源搜索引擎和分析平台,广泛用作基于关键字的文本搜索的文档存储。 Pinecone是一个广泛用于生产应用程序的向量数据库,例如语义搜索、推荐系统和威胁检测,需要在数亿甚…

【多模态】20、OVR-CNN | 使用 caption 来实现开放词汇目标检测

文章目录 一、背景二、方法2.1 学习 视觉-语义 空间2.2 学习开放词汇目标检测 三、效果 论文&#xff1a;Open-Vocabulary Object Detection Using Captions 代码&#xff1a;https://github.com/alirezazareian/ovr-cnn 出处&#xff1a;CVPR2021 Oral 一、背景 目标检测数…

关于rtthread的I/O设备模型

分层 从官方给的架构可以看出&#xff0c;官方是将IO设备的使用分成了三层。 IO设备管理层&#xff1a;也就是正常用户接触的一层&#xff0c;用户直接调用该层接口实现IO设备的操作。例如代码中的device.c文件 设备驱动框架层&#xff1a;这一层可以称为中间层了&#xff0c…