Linux -- 线程的优点、pthread 线程库

目录

线程的优点

pthread 线程库 

前言

认识线程库

简单验证线程的独立栈空间


线程的优点

与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少得多。

调度进程时,CPU 中有一个 cache(缓存,提高运行效率),CPU在虚拟地址转物理地址后,在内存中找到了一行代码,然而程序在运行时,比如运行到了第50行代码,下一次大概率会运行下一行代码,也就是第51行代码,也有可能跳转到其他代码,但是大概率还是运行下一行代码,所以系统把第50行代码的周边代码都加载到 cache 中,CPU 在运行时直接从 cache 中读取代码,提高 CPU 寻址效率。

进程切换时,会把当前缓存到 cache 的数据都切换掉,而线程切换时,寄存器中的数据会被切换,但 cache 中的数据不会被丢弃,大概率还是可以用的,线程切换只需要更改少量寄存器和栈指针等信息,而不需要像进程那样进行完整的上下文切换。所以线程切换时操作系统做的工作比进程的切换少。

创建一个新线程的代价要比创建一个新进程小得多,线程占用的资源比进程少得多。

进程是资源分配的基本单位,线程是调度的基本单位,当多个线程属于同一个进程时,它们会共享以下资源:

  1. 地址空间:包括代码段、数据段、堆区和栈区(每个线程有自己的栈)。所有线程都可以访问进程的整个虚拟地址空间,这意味着它们可以读写相同的全局变量和静态变量。

  2. 打开的文件描述符:如文件、网络连接等。所有线程都能操作这些描述符,因此对文件或网络连接的操作可以在不同线程间共享。

  3. 环境变量:进程启动时设置的环境变量是所有线程共有的。

  4. 内存映射:如果进程使用了内存映射文件或其他形式的内存映射,那么这些映射也是所有线程可见并可访问的。

  5. 信号处理程序:虽然信号通常是针对整个进程的,但某些信号(如SIGSEGV)可以由特定线程捕捉到,并且线程可以安装自己的信号处理器。

  6. 当前工作目录:所有线程共享同一进程的工作目录,任何线程改变工作目录都会影响其他线程。

  7. 用户ID和组ID:与安全性和权限相关的标识信息是所有线程共有的。

  8. 资源限制:例如最大文件大小、CPU时间等,这些限制适用于整个进程,因此也适用于所有线程。

因为多个线程共享资源,所以一个线程占用的资源比进程少。

但是线程也会有自己私有的资源

  1. 栈空间每个线程都有自己的栈,用于存储函数调用时的局部变量、返回地址等信息。这是线程之间保持独立性的关键之一,因为每个线程可以在其栈上进行独立的操作而不干扰其他线程。

  2. 寄存器集合(上下文数据):当线程被调度执行时,它有自己的寄存器集,包括程序计数器(PC)、堆栈指针和其他通用寄存器。这些寄存器保存了线程执行的状态信息。

  3. 线程ID:操作系统赋予每个线程一个唯一的标识符(TID),用于区分不同的线程。这个ID是线程私有的,因为它唯一地识别了一个线程。

  4. 线程优先级和调度属性:某些系统允许为每个线程设定独立的调度参数,如优先级和策略,这些属性影响线程的执行顺序和时间片分配。 

pthread 线程库 

前言

Linux 的线程是用进程模拟的,线程在Linux底层被视为轻量级进程。对于同一个进程中的新、主线程,可以看出线程的 tid 和 LWP 的数值是不一样的:

线程被创建、等待、分离、终止,且拥有独立的栈结构,这些都是系统在管理线程,

1、系统管理线程时,并没有对用户暴露 在系统中线程被视为轻量级进程的事实,用户认为那就是线程;

2、系统中没有线程的概念,只有轻量级进程的概念,用户却能创建管理、操作线程。

能实现以上两点是因为系统对底层的轻量级进程进行了封装,用户能操作线程都是因为有了库,所以在Linux中线程也叫做用户级线程。既然线程因库而起,就应该由库来维护。

认识线程库

为了管理线程,“先描述再组织”,定义线程的控制块 TCB,TCB是操作系统内核用来管理和调度线程的数据结构

#include <pthread.h>
 
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                  void *(*start_routine) (void *), void *arg);

pthread_create 的第一个参数 thread 是一个 pthread_t 类型的输出型参数,函数调用结束后,thread 指向一个虚拟内存单元,该内存单元的地址即为新创建线程的线程 ID,所以 pthread_t 类型的线程 ID 实际上就是一个进程地址空间的一个地址!线程库的后续操作就是根据该线程 ID 来操作线程的,用户也可以调用 pthread_self 函数来获得线程自身的 ID。

线程库中还包含了一系列用于创建、管理和操作线程的函数、类和数据结构。具体来说,一个典型的线程库会提供以下组件:

1. 线程管理

  • 创建线程:函数或构造函数用来启动一个新的线程,通常需要指定要在线程中执行的函数(即线程函数)。

    • 示例:pthread_create() (POSIX Threads)
  • 销毁/终止线程:方法来结束线程的执行,可以是自然结束(当线程函数返回时),也可以是通过特定API强制结束。

    • 示例:pthread_cancel()std::thread::join() 或 std::thread::detach()
  • 等待线程完成:允许主线程或其他线程等待某个特定线程完成其任务。

    • 示例:pthread_join()std::thread::join()

2. 线程同步机制

为了确保多个线程之间安全地共享资源,线程库提供了各种同步工具:

  • 互斥锁(Mutex):防止多个线程同时访问临界区代码段。

    • 示例:pthread_mutex_tstd::mutex
  • 读写锁(Read-write Locks):允许多个读者或单个写者访问资源。

    • 示例:pthread_rwlock_t
  • 条件变量(Condition Variables):用于线程间的通信,一个线程可以在满足特定条件时唤醒另一个线程。

    • 示例:pthread_cond_tstd::condition_variable
  • 信号量(Semaphores):控制对有限数量资源的访问。

    • 示例:sem_t (POSIX Semaphores)

3. 线程属性设置

  • 设置线程属性:在创建线程之前,可以设定一些线程属性,如栈大小、调度策略等。
    • 示例:pthread_attr_t (POSIX Threads)

4. 线程本地存储(TLS)

  • 线程局部数据:为每个线程提供独立的数据副本,即使这些变量是在全局范围内声明的。
    • 示例:pthread_key_create()pthread_getspecific()pthread_setspecific()std::thread_local (C++)

5. 高级特性

  • 线程池:预先创建一组工作线程,以便快速响应任务请求而不必频繁创建和销毁线程。

    • 示例: C++ 中可以通过第三方库如Boost实现。
  • 并发容器:线程安全的数据结构,例如队列、堆栈、哈希表等。

    • 示例:std::shared_timed_mutexconcurrent_queue (Intel TBB)
  • 原子操作:提供无锁编程的支持,保证某些操作的原子性。

    • 示例:std::atomic (C++)

6. 工具和辅助函数

  • 当前线程信息:获取当前线程ID等信息。

    • 示例:pthread_self()std::this_thread::get_id()
  • 线程调度:调整线程优先级或让出CPU给其他线程。

    • 示例:sched_yield()std::this_thread::yield()

简单验证线程的独立栈空间

#include<iostream>
#include<pthread.h>
#include<unistd.h>
using namespace std;
#include<string>

void* newthreadRun(void* args)
{
    std:string threadname=(char*)args;
    int cnt=5;
    while(true)
    {
       std::cout<<"I am "<<threadname<<",cnt: "<<cnt<<", &cnt: "<<&cnt<<std::endl;
       cnt--;
       sleep(1);
    }
    return nullptr;
}

int main()
{
    pthread_t tid1;
    pthread_t tid2;

    pthread_create(&tid1,nullptr,newthreadRun,(void*)"thread-1");   
    pthread_create(&tid2,nullptr,newthreadRun,(void*)"thread-2");

    pthread_join(tid2,nullptr);
    pthread_join(tid1,nullptr);

    return 0;
}

同一局部变量的地址不同, 说明每个线程的栈空间都私有一份该变量

 

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

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

相关文章

数字IC前端学习笔记:脉动阵列的设计方法学(四)

相关阅读 数字IC前端https://blog.csdn.net/weixin_45791458/category_12173698.html?spm1001.2014.3001.5482 引言 脉动结构&#xff08;也称为脉动阵列&#xff09;表示一种有节奏地计算并通过系统传输数据的处理单元(PEs)网络。这些处理单元有规律地泵入泵出数据以保持规则…

观察者模式和发布-订阅模式有什么异同?它们在哪些情况下会被使用?

大家好&#xff0c;我是锋哥。今天分享关于【观察者模式和发布-订阅模式有什么异同&#xff1f;它们在哪些情况下会被使用&#xff1f;】面试题。希望对大家有帮助&#xff1b; 观察者模式和发布-订阅模式有什么异同&#xff1f;它们在哪些情况下会被使用&#xff1f; 1000道 …

【LeetCode】726、原子的数量

【LeetCode】726、原子的数量 文章目录 一、递归: 嵌套类问题1.1 递归: 嵌套类问题 二、多语言解法 一、递归: 嵌套类问题 1.1 递归: 嵌套类问题 遇到 ( 括号, 则递归计算子问题 遇到大写字母, 或遇到 ( 括号, 则清算历史, 并开始新的记录 记录由两部分组成: 大写字母开头的 …

【Select 语法全解密】.NET开源ORM框架 SqlSugar 系列

系列文章目录 &#x1f380;&#x1f380;&#x1f380; .NET开源 ORM 框架 SqlSugar 系列 &#x1f380;&#x1f380;&#x1f380; 文章目录 系列文章目录前言一、Select 执行位置二、返回一个字段和多个字段三、单表返回DTO四、多表返回DTO4.1 手动DTO4.2 实体自动映射14.…

WebRTC服务质量(11)- Pacer机制(03) IntervalBudget

WebRTC服务质量&#xff08;01&#xff09;- Qos概述 WebRTC服务质量&#xff08;02&#xff09;- RTP协议 WebRTC服务质量&#xff08;03&#xff09;- RTCP协议 WebRTC服务质量&#xff08;04&#xff09;- 重传机制&#xff08;01) RTX NACK概述 WebRTC服务质量&#xff08;…

分布式协同 - 分布式事务_2PC 3PC解决方案

文章目录 导图Pre2PC&#xff08;Two-Phase Commit&#xff09;协议准备阶段提交阶段情况 1&#xff1a;只要有一个事务参与者反馈未就绪&#xff08;no ready&#xff09;&#xff0c;事务协调者就会回滚事务情况 2&#xff1a;当所有事务参与者均反馈就绪&#xff08;ready&a…

计算机图形学知识点汇总

一、计算机图形学定义与内容 1.图形 图形分为“图”和“形”两部分。 其中&#xff0c;“形”指形体或形状&#xff0c;存在于客观世界和虚拟世界&#xff0c;它的本质是“表示”&#xff1b;而图则是包含几何信息与属性信息的点、线等基本图元构成的画面&#xff0c;用于表达…

Nginx区分PC端和移动端访问

在使用Nginx时&#xff0c;可以通过$http_user_agent变量来判断用户访问的客户端类型&#xff0c;从而提供不同的内容或服务。下面是一个基于$http_user_agent变量来判断是否为PC访问的Nginx配置示例。 1. 理解$http_user_agent变量的含义及其在Nginx中的用途 $http_user_agen…

方法。。。

1. 方法概述 1.1 方法的概念 ​** 方法&#xff08;method&#xff09;是程序中最小的执行单元** 注意&#xff1a; 方法必须先创建才可以使用&#xff0c;该过程成为方法定义方法创建后并不是直接可以运行的&#xff0c;需要手动使用后&#xff0c;才执行&#xff0c;该过程…

jasypt原理

jasypt原理 一、背景知识二、原理分析1、(uml中蓝色)加载Encryptor、Detector和Resolver2、(uml中红色)加载EnableEncryptablePropertiesBeanFactoryPostProcessor3、(uml中绿色)解密过程 以jasypt 1.14为例 一、背景知识 需要了解spring的加载顺序&#xff1a; step1:主要是…

【UE5 C++课程系列笔记】13——GameInstanceSubsystem的简单使用

目录 概念 基本使用案例 效果 步骤 概念 UGameInstanceSubsystem 类继承自 USubsystem&#xff0c;它与 GameInstance 紧密关联&#xff0c;旨在为游戏提供一种模块化、可方便扩展和管理的功能单元机制。在整个游戏运行期间&#xff0c;一个 GameInstance 可以包含多个 UGa…

SpringCloud 系列教程:微服务的未来(二)Mybatis-Plus的条件构造器、自定义SQL、Service接口基本用法

本篇博客将深入探讨 MyBatis-Plus 的三个核心功能&#xff1a;条件构造器、自定义 SQL 和 Service 接口的基本用法。通过对这些功能的学习和掌握&#xff0c;开发者能够更加高效地使用 MyBatis-Plus 进行业务开发。 目录 前言 条件构造器 自定义SQL Service接口基本用法 总结…

我的 2024 年终总结

2024 年&#xff0c;我离开了待了两年的互联网公司&#xff0c;来到了一家聚焦教育机器人和激光切割机的公司&#xff0c;没错&#xff0c;是一家硬件公司&#xff0c;从未接触过的领域&#xff0c;但这还不是我今年最重要的里程碑事件 5 月份的时候&#xff0c;正式提出了离职…

STM32-笔记11-手写带操作系统的延时函数

1、为什么带操作系统的延时函数&#xff0c;和笔记10上的延时函数不能使用同一种&#xff1f; 因为笔记10的延时函数在每次调用的时候&#xff0c;会一直开关定时器&#xff0c;而在FreeRTOS操作系统中&#xff0c;SysTick定时器当作时基使用。 时基是一个时间显示的基本单位。…

人工智能与物联网:从智慧家居到智能城市的未来蓝图

引言&#xff1a;未来已来&#xff0c;智能化的世界 想象一下&#xff0c;一个早晨&#xff0c;智能闹钟根据你的睡眠状态自动调整叫醒时间&#xff0c;咖啡机早已备好热腾腾的咖啡&#xff0c;窗帘缓缓拉开&#xff0c;迎接清晨的阳光。这不是科幻小说中的场景&#xff0c;而是…

流程控制

第一章 流程控制语句 在一个程序执行的过程中&#xff0c;各条语句的执行顺序对程序的结果是有直接影响的。所以&#xff0c;我们必须清楚每条语句的执行流程。而且&#xff0c;很多时候要通过控制语句的执行顺序来实现我们想要的功能。 1.1 流程控制语句分类 ​ 顺序结构 …

台球助教平台系统开发APP和小程序信息收藏功能需求解析(第十二章)

以下是开发台球助教系统客户端&#xff08;APP&#xff0c;小程序&#xff0c;H5&#xff09;几端的信息收藏功能的详细需求和功能说明&#xff0c;内容比较详细&#xff0c;可以说是一个教科书式的详细说明了&#xff0c;这套需求说明不仅仅用在我们的台球助教系统程序上&…

RISC-V 医疗芯片发展方向探究及展望

&#xff08;一&#xff09;研究背景与意义 近年来&#xff0c;RISC-V作为一种开源指令集架构在芯片领域迅速兴起。它起源于加州大学伯克利分校&#xff0c;于2011年首次公开发布&#xff0c;后凭借其独特优势吸引了全球众多企业、机构以及科研人员的关注与参与。RISC-V具有开…

三维动画的常用“视觉特效”有哪些?

在当今的视觉盛宴中&#xff0c;三维动画技术宛如一位神奇的魔法师&#xff0c;为视觉特效&#xff08;VFX&#xff09;领域施下了变革的咒语。从大荧幕上的震撼电影&#xff0c;到让人沉浸其中的视频游戏&#xff0c;再到夺人眼球的广告以及精细的模拟场景&#xff0c;三维动画…

【EtherCATBasics】- KRTS C++示例精讲(2)

EtherCATBasics示例讲解 目录 EtherCATBasics示例讲解结构说明代码讲解 项目打开请查看【BaseFunction精讲】。 结构说明 EtherCATBasics&#xff1a;应用层程序&#xff0c;主要用于人机交互、数据显示、内核层数据交互等&#xff1b; EtherCATBasics.h &#xff1a; 数据定义…