【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 logicprintf("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 detachableif (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 exitssleep(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 logicprintf("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 typeint 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.mzph.cn/news/14733.shtml

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

相关文章

Bean的作用域和生命周期

1. Bean的作用域 Bean作用域定义了对象实例在应用程序中的生命周期和访问范围&#xff0c;⽐如 singleton 单例作⽤域&#xff0c;就 表示 Bean 在整个 Spring 中只有⼀份&#xff0c;它是全局共享的&#xff0c;那么当其他⼈修改了这个值之后&#xff0c;那么另⼀ 个⼈读取到…

【LeetCode】102.二叉树的层序遍历

题目 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,20],[15,7]]示例 2&#xff1a; …

【小梦C嘎嘎——启航篇】类和对象(上篇)

【小梦C嘎嘎——启航篇】类和对象&#xff08;上篇&#xff09;&#x1f60e; 前言&#x1f64c;什么是面向过程&#xff1f;什么是面向对象&#xff1f;什么是类和对象类中的访问权限属性类的大小计算this 指针构造函数析构函数 总结撒花&#x1f49e; &#x1f60e;博客昵称&…

Node.js介绍;浏览器和Node.j架构区别;Node的安装与管理;JS代码执行方式;Node的输入与输出;全局对象;

目录 1_Node.js介绍1.1_概念1.2_浏览器和Node.j架构区别1.3_Node.js应用场景 2_Node的安装与管理2.1_安装2.2_Node的版本工具2.3_版本管理工具&#xff1a;n 3_JavaScript代码执行4_Node的输入与输出4.1_REPL4.2_Node程序传递参数4.3_Node的输出 5_全局对象5.1_常见的全局对象5…

FreeRTOS学习之路,以STM32F103C8T6为实验MCU(2-1:任务)

学习之路主要为FreeRTOS操作系统在STM32F103&#xff08;STM32F103C8T6&#xff09;上的运用&#xff0c;采用的是标准库编程的方式&#xff0c;使用的IDE为KEIL5。 注意&#xff01;&#xff01;&#xff01;本学习之路可以通过购买STM32最小系统板以及部分配件的方式进行学习…

大数据实时链路备战 —— 数据双流高保真压测 | 京东云技术团队

一、大数据双流建设 1.1 数据双流 大数据时代&#xff0c;越来越多的业务依赖实时数据用于决策&#xff0c;比如促销调整&#xff0c;点击率预估、广告分佣等。为了保障业务的顺利开展&#xff0c;也为了保证整体大数据链路的高可用性&#xff0c;越来越多的0级系统建设双流&…

java之juc

juc是java.util.current的简写&#xff0c;意思是并发编程。 锁是什么&#xff1f;如何判断锁的是谁&#xff1f; 生产者和消费者问题 synchronized版本 package com.demo.juc.pc;/*** 线程之间的通信问题&#xff0c;生产者和消费者问题&#xff01;* 线程交替执行** a b …

ubuntu初始化/修改root密码

1.登录ubuntu后&#xff0c;使用sudo passwd root命令&#xff0c;进行root密码的初始化/修改&#xff0c;注&#xff1a;这里需要保证两次输入的密码都是同一个&#xff0c;才可成功 ubuntugt-ubuntu22-04-cmd-v1-0-32gb-100m:~/ocr$ sudo passwd root New password: Retype…

Docker 安全 Docker HTTPS请求过程与配置

Docker 容器安全注意点 尽量别做的事 尽量不用 --privileged 运行容器&#xff08;授权容器root用户拥有宿主机的root权限&#xff09; 尽量不用 --network host 运行容器&#xff08;使用 host 网络模式共享宿主机的网络命名空间&#xff09; 尽量不在容器中运行 ssh 服务 尽…

文件按关键字分组-切割-染色-写入excel

1. 背景 针对下面的文件data.csv&#xff0c;首先根据fid进行排序&#xff0c;然后分组&#xff0c;使相同fid的记录放到同一个excel文件中&#xff0c;并对每列重复的数据元素染上红色。 fid,user_id -1000078398032092029,230410010036537520 -1000078398032092029,23042301…

Gitlab 备份与恢复

备份 1、备份数据&#xff08;手动备份&#xff09; gitlab-rake gitlab:backup:create2、备份数据&#xff08;定时任务备份&#xff09; [rootlocalhost ]# crontab -l 00 1 * * * /opt/gitlab/bin/gitlab-rake gitlab:backup:create 说明&#xff1a;每天凌晨1点备份数据…

什么是 HTTP 长轮询?

什么是 HTTP 长轮询&#xff1f; Web 应用程序最初是围绕客户端/服务器模型开发的&#xff0c;其中 Web 客户端始终是事务的发起者&#xff0c;向服务器请求数据。因此&#xff0c;没有任何机制可以让服务器在没有客户端先发出请求的情况下独立地向客户端发送或推送数据。 为…

Docker 全栈体系(八)

Docker 体系&#xff08;高级篇&#xff09; 六、Docker轻量级可视化工具Portainer 1. 是什么 Portainer 是一款轻量级的应用&#xff0c;它提供了图形化界面&#xff0c;用于方便地管理Docker环境&#xff0c;包括单机环境和集群环境。 2. 安装 官网 https://www.portain…

计算机视觉常用数据集介绍

1 MINIST MINIST 数据集应该算是CV里面最早流行的数据了&#xff0c;相当于CV领域的Hello World。该数据包含70000张手写数字图像&#xff0c;其中60000张用于train&#xff0c; 10000张用于test&#xff0c; 并且都有相应的label。图像的尺寸比较小&#xff0c; 为28x28。 数…

数据安全

数据的备份与恢复 1. 数据备份技术 任何数据在长期使用过程中&#xff0c;都存在一定的安全隐患。由于认为操作失误或系统故障&#xff0c;例如认为错误、程序出错、计算机失效、灾难和偷窃&#xff0c;经常造成数据丢失&#xff0c;给个人和企业造成灾难性的影响。在这种情况…

DPN(Dual Path Network)网络结构详解

论文&#xff1a;Dual Path Networks 论文链接&#xff1a;https://arxiv.org/abs/1707.01629 代码&#xff1a;https://github.com/cypw/DPNs MXNet框架下可训练模型的DPN代码&#xff1a;https://github.com/miraclewkf/DPN 我们知道ResNet&#xff0c;ResNeXt&#xff0c;D…

Android启动速度优化

本节主要内容&#xff1a;了解APP启动流程、启动状态、查看启动时间、CPU Profile定位启动耗时代码、StrictMode严苛模式检测不合理写法、解决启动黑白屏问题。 一、APP启动流程 ①用户点击桌面App图标&#xff0c;Launcher进程采用Binder IPC向system_server进程发起startAc…

DHCP部署与安全详解

文章目录 一、DHCP是什么&#xff1f;二、DHCP相关概念三、DHCP优点四、DHCP原理1. 客户机发送DHCP Discovery广播包&#xff08;发现谁是DHCP服务器&#xff09;2. 服务器响应DHCP Offer广播包3. 客户机发送DHCP Request广播包4. 服务器发送DHCP ACK广播包 五、DHCP续约六、部…

lc209.长度最小的子数组

暴力破解&#xff1a;二次for循环遍历num[i]...num[j]&#xff0c;记录满足条件的最小长度 前缀和二分&#xff1a;前缀和降低计算num[i]...num[j]的时间复杂度 对前缀和数组中的每个数进行遍历&#xff0c;找到距离这个数满足条件的最小长度 前缀和数组单调递增&#xff0c;此…

【JAVA】java中的逻辑控制

作者主页&#xff1a;paper jie的博客 本文作者&#xff1a;大家好&#xff0c;我是paper jie&#xff0c;感谢你阅读本文&#xff0c;欢迎一建三连哦。 本文录入于《JAVASE语法系列》专栏&#xff0c;本专栏是针对于大学生&#xff0c;编程小白精心打造的。笔者用重金(时间和精…