深入Linux轻量级进程管理:线程创建、线程ID解析与进程地址空间页表探究

本文主要是介绍深入Linux轻量级进程管理:线程创建、线程ID解析与进程地址空间页表探究,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

🍑个人主页:Jupiter.
🚀 所属专栏:Linux从入门到进阶
欢迎大家点赞收藏评论😊

在这里插入图片描述

在这里插入图片描述

目录

  • `🚲Linux线程控制`
    • `🐏POSIX线程库`
    • `🐕创建线程`
      • `🐟指令查看轻量级进程`
          • `指令:ps -aL`
    • `🐒线程ID及进程地址空间布局`
            • *pthread_t 到底是什么类型呢?*
      • `🦔__thread与线程的局部存储`


🚲Linux线程控制

🐏POSIX线程库

在Linux中,没有线程的概念,只有轻量级进程的概念,所以Linux系统只提供了轻量级进程的系统调用,没有线程相关的系统调用,但是用户不知道轻量级进程的概念,只知道线程和进程,所以Linux将轻量级进程的系统调用进行封装,转成线程相关的接口语义提供给用户,就形成了pthread库

  • 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以“pthread_”开头的。
  • 要使用这些函数库,要通过引入头文<pthread.h>
  • 链接这些线程函数库时要使用编译器命令“-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变量的开销更小。

注意:新线程和主线程谁先运行?这是未知的。

示例代码:

#include <iostream>
#include <unistd.h>
#include <pthread.h>void *routine(void *name)
{std::cout << "i am new thread,name:" << (char *)name << std::endl;sleep(1);return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, routine, (void *)("thread-1"));while (true){std::cout << "i am process,pid:" << getpid() << std::endl;sleep(1);}return 0;
}

运行结果:

🐟指令查看轻量级进程

指令:ps -aL

根据上面的结果可知:他们的pid一样,所以属于同一个进程,而且可知:OS在进行调度的时候,用的是LWP进行调度的。(因为pid可能一样,不能唯一性标识)

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

  • pthread_ create函数会产生一个线程ID,存放在第一个参数指向的地址中。

  • 前面讲的线程ID属于进程调度的范畴。因为线程是轻量级进程是操作系统调度器的最小单位,所以需要一个数值来唯一表示该线程。

  • pthread_ create函数第一个参数指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程ID,属于NPTL线程库的范畴。线程库的后续操作,就是根据该线程ID来操作线程的。

线程库NPTL提供了pthread_ self函数,可以获得线程自身的ID

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

  • 线程的管理库维护,即描述线程的结构体与管理线程的数据结构(类似于数组)就在库里面的,其中pthread_t tid即是描述tid线程结构体的起始地址

  • 线程的栈与局部存储是在库中维护的。虽然栈是线程独立的,但是其他线程也是可以访问的。

示例代码:

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <stdio.h>
std::string ToHex(pthread_t tid)   //将id转换为十六进制
{char buff[64];snprintf(buff, 64, "0x%lx", tid);return buff;
}void *routine(void *name)
{while (true){sleep(1);std::cout << "i am new thread,name:" << (char *)name << "  my tid is :" << ToHex(pthread_self()) << std::endl;}return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid, nullptr, routine, (void *)("thread-1"));while (true){std::cout << "i am process,pid:" << getpid() << "  new thread id:" << ToHex(tid) << std::endl;sleep(1);}return 0;
}

运行结果:
在这里插入图片描述

🦔__thread与线程的局部存储

  • __thread 是 C 和 C++ 中用于声明线程局部存储的一个关键字(或属性,具体取决于编译器和平台)。它告诉编译器或链接器,被 __thread 修饰的变量是每个线程私有的,即每个线程都有该变量的一个独立实例,这些实例之间互不影响。如:__thread int tls_variable = 0; 一般对于全局变量使用。
    示例代码:
#include <pthread.h>  
#include <stdio.h>  // 声明一个线程局部变量  
__thread int tls_variable = 0;  void* thread_function(void* arg) 
{  tls_variable = (int)arg; // 每个线程都会修改它自己的 tls_variable 副本  printf("Thread %ld has tls_variable = %d\n", (long)pthread_self(), tls_variable);  return NULL;  
}  int main() {  pthread_t threads[2];  // 创建两个线程,每个线程将接收到一个不同的参数  pthread_create(&threads[0], NULL, thread_function, (void*)1);  pthread_create(&threads[1], NULL, thread_function, (void*)2);  // 等待两个线程完成  pthread_join(threads[0], NULL);  pthread_join(threads[1], NULL);  return 0;  
}

这篇关于深入Linux轻量级进程管理:线程创建、线程ID解析与进程地址空间页表探究的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1140738

相关文章

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

JDK21对虚拟线程的几种用法实践指南

《JDK21对虚拟线程的几种用法实践指南》虚拟线程是Java中的一种轻量级线程,由JVM管理,特别适合于I/O密集型任务,:本文主要介绍JDK21对虚拟线程的几种用法,文中通过代码介绍的非常详细,... 目录一、参考官方文档二、什么是虚拟线程三、几种用法1、Thread.ofVirtual().start(

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

k8s按需创建PV和使用PVC详解

《k8s按需创建PV和使用PVC详解》Kubernetes中,PV和PVC用于管理持久存储,StorageClass实现动态PV分配,PVC声明存储需求并绑定PV,通过kubectl验证状态,注意回收... 目录1.按需创建 PV(使用 StorageClass)创建 StorageClass2.创建 PV

一文解析C#中的StringSplitOptions枚举

《一文解析C#中的StringSplitOptions枚举》StringSplitOptions是C#中的一个枚举类型,用于控制string.Split()方法分割字符串时的行为,核心作用是处理分割后... 目录C#的StringSplitOptions枚举1.StringSplitOptions枚举的常用

Python函数作用域与闭包举例深度解析

《Python函数作用域与闭包举例深度解析》Python函数的作用域规则和闭包是编程中的关键概念,它们决定了变量的访问和生命周期,:本文主要介绍Python函数作用域与闭包的相关资料,文中通过代码... 目录1. 基础作用域访问示例1:访问全局变量示例2:访问外层函数变量2. 闭包基础示例3:简单闭包示例4