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

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.mfbz.cn/a/51460.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RNN架构解析——传统RNN模型

目录 传统RNN的内部结构图使用RNN优点和缺点 传统RNN的内部结构图 使用RNN rnnnn.RNN(5,6,1) #第一个参数是输入张量x的维度&#xff0c;第二个是隐藏层维度&#xff0c;第三层是隐藏层的层数 input1torch.randn(1,3,5) #第一个是输入序列的长度&#xff0c;第二个是批次的样本…

网络层IP协议的基本原理 数据链路层ARP协议 域名解析以及一些重要技术

目录 1 网络层IP协议协议头格式网段划分DHCPCIDR&#xff1a;基于子网掩码的划分方式特殊的IP号IP地址的数量限制私有IP地址和公网IP地址路由路由表 2 数据链路层 — 局域网的转发问题以太网认识以太网以太网帧格式局域网通信原理 MTUMTU对IP协议的影响MTU对UDP协议的影响MTU对…

自动化测试——APP测试

一、环境配置 1、安装jdk 配置环境变量 2、Android SDK 环境安装 3、Appium Server安装 4、模拟器安装 5、安装appium-python-client Python第三方库 二、APP自动化测试原理 三、Desired Capabilites——APPium自动化配置项 1、设置参数 2、操作系统 3、选择版本 4、设备名称…

CAN转EtherNet/IP网关can协议破解服务

JM-EIP-CAN 是自主研发的一款 ETHERNET/IP 从站功能的通讯网关。该产品主要功能是将各种 CAN 总线和 ETHERNET/IP 网络连接起来。 本网关连接到 ETHERNET/IP 总线中做为从站使用&#xff0c;连接到 CAN 总线中根据节点号进行读写。 技术参数 ETHERNET/IP 技术参数 网关做为 …

选择器jQuery

诚信是你价格不菲的鞋子&#xff0c;踏遍千山万水&#xff0c;质量也应永恒不变。 jQuery选择器大全总结&#xff1a; jQuery选择器是一种用于在HTML文档中选择元素的强大工具。下面是一些常用的jQuery选择器的总结&#xff1a; 基本选择器&#xff1a; 元素选择器&#xff1a…

HarmonyOS/OpenHarmony元服务开发-卡片使用动效能力

ArkTS卡片开放了使用动画效果的能力&#xff0c;支持显式动画、属性动画、组件内转场能力。需要注意的是&#xff0c;ArkTS卡片使用动画效果时具有以下限制&#xff1a; 以下示例代码实现了按钮旋转的动画效果&#xff1a; Entry Component struct AttrAnimationExample { St…

生命在于学习——APP渗透学习笔记

一、app渗透篇 1、Android 简介 自从 Android 被谷歌收购&#xff08;2005 年&#xff09;&#xff0c;谷歌已经完成了整个开发&#xff0c;在过去的 9 年里&#xff0c;尤其是在安全方面&#xff0c;有很多变化。 现在&#xff0c;它是世界上最广泛使用的智能手机平台&#…

PHP使用Redis实战实录4:单例模式和面向过程操作redis的语法

PHP使用Redis实战实录系列 PHP使用Redis实战实录1&#xff1a;宝塔环境搭建、6379端口配置、Redis服务启动失败解决方案PHP使用Redis实战实录2&#xff1a;Redis扩展方法和PHP连接Redis的多种方案PHP使用Redis实战实录3&#xff1a;数据类型比较、大小限制和性能扩展PHP使用Re…

IT技术面试必备:如何做好IT类技术面试?

博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客&#x1f466;&#x1f3fb; 《java 面试题大全》 &#x1f369;惟余辈才疏学浅&#xff0c;临摹之作或有不妥之处&#xff0c;还请读者海涵指正。☕&#x1f36d; 《MYSQL从入门到精通》数据库是开发者必会基础之…

tinkerCAD案例:25. 量角器 - 测量角度

tinkerCAD案例&#xff1a;25. 量角器 - 测量角度 原文 Now we’re going to make a protractor! A Protractor is one of the most basic, but essential, tools for making measurements. It is, then, surprising that the modern protractor is barely over 200 years ol…

神经网络简单介绍

人工神经网络(artififial neural network) 简称神经网络&#xff0c;它是一种模仿生物神经网络结构和功能的非线性数学模型。 神经网络通过输入层接受原始特征信息&#xff0c;再通过隐藏层进行特征信息的加工和提取&#xff0c;最后通过输出层输出结果。 根据需要神经网络可以…

【机器学习】Linear Regression

Model Representation 1、问题描述2、表示说明3、数据绘图4、模型函数5、预测总结附录 1、问题描述 一套 1000 平方英尺 (sqft) 的房屋售价为300,000美元&#xff0c;一套 2000 平方英尺的房屋售价为500,000美元。这两点将构成我们的数据或训练集。面积单位为 1000 平方英尺&a…

数据可视化 - 动态柱状图

基础柱状图 通过Bar构建基础柱状图 from pyecharts.charts import Bar from pyecharts.options import LabelOpts # 使用Bar构建基础柱状图 bar Bar() # 添加X轴 bar.add_xaxis(["中国", "美国", "英国"]) # 添加Y轴 # 设置数值标签在右侧 b…

乌班图22.04安装wireguard实现异地组网

1. 前言&#xff1a; wireguard是新型的异地组网工具&#xff0c;在此之前&#xff0c;又已经被抛弃的pptp&#xff0c;l2tp&#xff0c;有配置复杂的openvpn&#xff0c;wireguard被linux作者linus赞叹优雅&#xff0c;于linux 5.6合并至linux内核主线。 2. 安装过程&#…

【1.3】Java微服务:Spring Cloud版本说明

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; 微服务 ✨特色专栏&#xff1a; 知识分享 &#x…

【Java面试丨消息中间件】Kafka

一、kafka是如何保证消息不丢失 1. 介绍 使用kafka在消息的收发过程都有可能会出现消息丢失 &#xff08;1&#xff09;生产者发送消息到broker丢失 &#xff08;2&#xff09;消息在broker中存储丢失 &#xff08;3&#xff09;消费者从broker接收消息丢失 2. 生产者发送消…

Day47 算法记录|动态规划14子序列

子序列 1143. 最长公共子序列1035.不相交的线53. 最大子数组和 1143. 最长公共子序列 这道题和718. 最长重复子数组的区别&#xff1a;这道题的子序列可以不连续 这个视频讲解的很好 class Solution {public int longestCommonSubsequence(String text1, String text2) {char…

[Linux]线程基本知识

概念 进程 一个正在执行的程序&#xff0c;它是资源分配的最小单位 进程中的事情需要按照一定的顺序逐个进行 进程出现了很多弊端: 一是由于进程是资源拥有者&#xff0c;创建、撤消与切换存在较大的时空开销&#xff0c;因此需要引入轻型进程&#xff1b; 二是由于对称多…

高德地图JS API升级到2.0版本

项目上反馈高德地图底图信息更新不及时&#xff0c;不利于进行点位规划。经研究发现高德地图JS API 1.4.15版本相对于2.0版本&#xff0c;确实地图切片上的标注信息较少。通过工单的形式询问高德的技术工程师认识到1.4.15版本数据更新有延迟&#xff0c;1.4.15版本地图的数据以…

【微软知识】微软相关技术知识分享

微软技术领域 一、微软操作系统&#xff1a; 微软的操作系统主要是 Windows 系列&#xff0c;包括 Windows 10、Windows Server 等。了解 Windows 操作系统的基本使用、配置和故障排除是非常重要的。微软操作系统&#xff08;Microsoft System&#xff09;是美国微软开发的Wi…