【Linux探索学习】第二十九弹——线程概念:Linux线程的基本概念与线程控制详解

news2025/4/1 21:29:49

Linux学习笔记:

https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482

前言:

在现代操作系统中,线程是程序执行流的最小单元。与进程相比,线程更加轻量级,创建和销毁的开销更小,且线程之间可以共享内存空间,因此在多任务处理、并发编程中,线程的使用非常广泛。Linux作为一个多用户、多任务的操作系统,提供了强大的线程支持。本文将详细介绍Linux中线程的基本概念以及线程控制的相关知识,并通过代码示例帮助读者更好地理解。

目录

一、线程的基本概念

1.1 什么是线程?

1.2 线程与进程的区别

1.3 线程的优点

1.4 线程的缺点

二、Linux中的线程模型

2.1 用户级线程与内核级线程

2.2 Linux的线程实现

三、线程控制

3.1 线程的创建与终止

3.1.1 创建线程

3.1.2 终止线程

3.2 线程的属性

3.3 线程的取消

3.4 线程的清理

四、线程分离

4.1 什么是线程分离?

4.2 设置线程为分离状态

4.3 线程分离的注意事项

五、线程的调度

5.1 线程的调度策略

5.2 设置线程的调度策略

五、总结


一、线程的基本概念

1.1 什么是线程?

线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个进程可以包含多个线程,这些线程共享进程的资源(如内存、文件描述符等),但每个线程拥有独立的执行栈和程序计数器。

线程其实就是我们之前所讲的进程的延申,进程实际上是可以由多个执行流组成的,这些执行流其实就叫做线程,我们之前所讲的进程实际上就是只有单执行流的特殊情况,进程实际上可以看作资源分配的实体,线程就是资源分配的基本单位

1.2 线程与进程的区别

特性进程线程
定义程序的一次执行,拥有独立的内存空间进程中的一个执行流,共享进程的内存空间
资源开销较大,创建和销毁开销大较小,创建和销毁开销小
通信方式进程间通信(IPC)机制复杂线程间通信简单,直接共享内存
上下文切换开销大开销小
独立性独立,互不影响依赖进程,线程间相互影响

1.3 线程的优点

  1. 响应性:多线程程序可以在一个线程等待I/O时,另一个线程继续执行,从而提高程序的响应性。

  2. 资源共享:线程共享进程的内存空间,因此线程间的数据共享和通信更加方便。

  3. 经济性:创建和销毁线程的开销比进程小,且线程切换的开销也比进程小。

  4. 多核利用:多线程程序可以充分利用多核CPU的并行计算能力。

1.4 线程的缺点

  1. 同步问题:多个线程共享同一进程的资源,容易引发竞态条件等问题。

  2. 调试困难:多线程程序的调试比单线程程序复杂,因为线程的执行顺序是不确定的。

  3. 资源竞争:多个线程竞争同一资源时,可能导致性能下降。

这些问题我们会在后面的章节进行解决,尤其是线程的同步与互斥问题是很重要的,我们后面会进行讲解

二、Linux中的线程模型

2.1 用户级线程与内核级线程

在Linux中,线程的实现可以分为用户级线程和内核级线程。

  • 用户级线程:由用户空间的线程库(如POSIX线程库)管理,内核并不知道这些线程的存在。用户级线程的创建、调度、同步等操作都由线程库在用户空间完成。优点是线程切换开销小,缺点是无法利用多核CPU的并行能力。

  • 内核级线程:由操作系统内核管理,内核知道每个线程的存在,并负责线程的调度。内核级线程的创建、调度、同步等操作都需要通过系统调用来完成。优点是可以利用多核CPU的并行能力,缺点是线程切换开销较大。

2.2 Linux的线程实现

Linux通过轻量级进程(Lightweight Process, LWP)来实现线程。每个线程在内核中都有一个对应的轻量级进程,这些轻量级进程共享同一地址空间和其他资源。Linux的线程库(如NPTL)提供了对POSIX线程标准的支持。我们可以理解为Linux的线程实现就是用户层的,因为Linux中并没有线程的概念,有的只是轻量级进程的概念,是通过在用户层进行封装来实现的

三、线程控制

3.1 线程的创建与终止

在Linux中,线程的创建和终止是通过POSIX线程库(pthread)来实现的。下面我们通过代码示例来讲解线程的创建与终止。

3.1.1 创建线程

在POSIX线程库中,使用pthread_create函数来创建线程。该函数的原型如下:

#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg);
  • thread:指向线程标识符的指针。

  • attr:用于设置线程属性,通常为NULL,表示使用默认属性。

  • start_routine:线程函数的起始地址,线程创建后会执行该函数。

  • arg:传递给线程函数的参数。

下面是一个简单的线程创建示例:

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

void* thread_function(void* arg) {
    printf("Thread is running...\n");
    sleep(2);
    printf("Thread is exiting...\n");
    return NULL;
}

int main() {
    pthread_t thread_id;
    int ret = pthread_create(&thread_id, NULL, thread_function, NULL);
    if (ret != 0) {
        printf("Thread creation failed!\n");
        return 1;
    }
    printf("Main thread is running...\n");
    pthread_join(thread_id, NULL);  // 等待线程结束
    printf("Main thread is exiting...\n");
    return 0;
}

运行结果:

在这个示例中,主线程创建了一个新线程,新线程执行thread_function函数。主线程通过pthread_join函数等待新线程结束。

3.1.2 终止线程

线程可以通过以下方式终止:

  1. 正常返回:线程函数执行完毕并返回,线程自动终止。

  2. 调用pthread_exit:线程可以调用pthread_exit函数主动终止自己。

  3. 被其他线程取消:其他线程可以调用pthread_cancel函数取消指定线程。

下面是一个使用pthread_exit终止线程的示例:

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

void* thread_function(void* arg) {
    printf("Thread is running...\n");
    sleep(2);
    printf("Thread is exiting...\n");
    pthread_exit(NULL);  // 主动终止线程
}

int main() {
    pthread_t thread_id;
    int ret = pthread_create(&thread_id, NULL, thread_function, NULL);
    if (ret != 0) {
        printf("Thread creation failed!\n");
        return 1;
    }
    printf("Main thread is running...\n");
    pthread_join(thread_id, NULL);  // 等待线程结束
    printf("Main thread is exiting...\n");
    return 0;
}

运行结果:

3.2 线程的属性

线程的属性可以通过pthread_attr_t结构体来设置。常见的线程属性包括:

  • 线程的分离状态:线程可以是可连接的(joinable)或分离的(detached)。可连接的线程在终止后需要其他线程调用pthread_join来回收资源,而分离的线程在终止后会自动释放资源。

  • 线程的栈大小:可以设置线程的栈大小。

  • 线程的调度策略:可以设置线程的调度策略(如FIFO、轮转等)。

下面是一个设置线程属性的示例:

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

void* thread_function(void* arg) {
    printf("Thread is running...\n");
    sleep(2);
    printf("Thread is exiting...\n");
    return NULL;
}

int main() {
    pthread_t thread_id;
    pthread_attr_t attr;
    pthread_attr_init(&attr);  // 初始化线程属性
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);  // 设置线程为分离状态

    int ret = pthread_create(&thread_id, &attr, thread_function, NULL);
    if (ret != 0) {
        printf("Thread creation failed!\n");
        return 1;
    }
    printf("Main thread is running...\n");
    sleep(3);  // 主线程等待一段时间,确保子线程执行完毕
    printf("Main thread is exiting...\n");
    pthread_attr_destroy(&attr);  // 销毁线程属性
    return 0;
}

运行结果:

在这个示例中,我们通过pthread_attr_setdetachstate函数将线程设置为分离状态,这样线程在终止后会自动释放资源,主线程不需要调用pthread_join来等待线程结束。

3.3 线程的取消

线程可以通过pthread_cancel函数来取消。被取消的线程会在下一个取消点(cancellation point)终止。取消点通常是某些系统调用或库函数,如sleepreadwrite等。

下面是一个线程取消的示例:

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

void* thread_function(void* arg) {
    printf("Thread is running...\n");
    while (1) {
        printf("Thread is working...\n");
        sleep(1);
    }
    return NULL;
}

int main() {
    pthread_t thread_id;
    int ret = pthread_create(&thread_id, NULL, thread_function, NULL);
    if (ret != 0) {
        printf("Thread creation failed!\n");
        return 1;
    }
    sleep(3);  // 主线程等待3秒
    pthread_cancel(thread_id);  // 取消线程
    printf("Thread has been canceled.\n");
    pthread_join(thread_id, NULL);  // 等待线程结束
    printf("Main thread is exiting...\n");
    return 0;
}

运行结果:

在这个示例中,主线程在3秒后取消了子线程,子线程在sleep函数处被取消。

3.4 线程的清理

线程在终止时可能需要执行一些清理操作,如释放资源、关闭文件等。POSIX线程库提供了pthread_cleanup_pushpthread_cleanup_pop函数来注册和注销清理函数。

下面是一个线程清理的示例:

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

void cleanup_function(void* arg) {
    printf("Cleanup function is called: %s\n", (char*)arg);
}

void* thread_function(void* arg) {
    pthread_cleanup_push(cleanup_function, "Resource 1");
    pthread_cleanup_push(cleanup_function, "Resource 2");

    printf("Thread is running...\n");
    sleep(2);
    printf("Thread is exiting...\n");

    pthread_cleanup_pop(1);  // 执行清理函数
    pthread_cleanup_pop(1);  // 执行清理函数
    return NULL;
}

int main() {
    pthread_t thread_id;
    int ret = pthread_create(&thread_id, NULL, thread_function, NULL);
    if (ret != 0) {
        printf("Thread creation failed!\n");
        return 1;
    }
    pthread_join(thread_id, NULL);  // 等待线程结束
    printf("Main thread is exiting...\n");
    return 0;
}

在这个示例中,我们使用pthread_cleanup_push注册了两个清理函数,当线程终止时,这些清理函数会被自动调用。

四、线程分离

4.1 什么是线程分离?

线程分离(Detached Thread)是指线程在终止后自动释放其资源,而不需要其他线程调用pthread_join来回收资源。分离线程通常用于不需要返回结果的场景。

4.2 设置线程为分离状态

可以通过pthread_detach函数将线程设置为分离状态。下面是一个线程分离的示例:

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

void* thread_function(void* arg) {
    printf("Thread is running...\n");
    sleep(2);
    printf("Thread is exiting...\n");
    return NULL;
}

int main() {
    pthread_t thread_id;
    int ret = pthread_create(&thread_id, NULL, thread_function, NULL);
    if (ret != 0) {
        printf("Thread creation failed!\n");
        return 1;
    }
    pthread_detach(thread_id);  // 将线程设置为分离状态
    printf("Main thread is running...\n");
    sleep(3);  // 主线程等待一段时间,确保子线程执行完毕
    printf("Main thread is exiting...\n");
    return 0;
}

在这个示例中,我们通过pthread_detach函数将线程设置为分离状态。分离状态的线程在终止后会自动释放资源,主线程不需要调用pthread_join来等待线程结束。

4.3 线程分离的注意事项

  1. 资源释放:分离线程在终止时会自动释放资源,因此不需要调用pthread_join来回收资源。

  2. 无法获取返回值:分离线程的返回值无法被其他线程获取,因为线程终止后资源已经被释放。

  3. 线程状态:一旦线程被设置为分离状态,就不能再通过pthread_join来等待线程结束。

五、线程的调度

5.1 线程的调度策略

Linux中的线程调度策略主要有以下几种:

  • SCHED_FIFO:先进先出调度策略,优先级高的线程会一直运行,直到它主动放弃CPU。

  • SCHED_RR:轮转调度策略,优先级高的线程会运行一段时间(时间片),然后让出CPU给其他相同优先级的线程。

  • SCHED_OTHER:默认的调度策略,基于时间片的动态优先级调度。

5.2 设置线程的调度策略

可以通过pthread_setschedparam函数来设置线程的调度策略和优先级。下面是一个设置线程调度策略的示例:

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

void* thread_function(void* arg) {
    printf("Thread is running...\n");
    sleep(2);
    printf("Thread is exiting...\n");
    return NULL;
}

int main() {
    pthread_t thread_id;
    pthread_attr_t attr;
    struct sched_param param;

    pthread_attr_init(&attr);
    pthread_attr_setschedpolicy(&attr, SCHED_FIFO);  // 设置调度策略为FIFO
    param.sched_priority = 50;  // 设置优先级
    pthread_attr_setschedparam(&attr, &param);

    int ret = pthread_create(&thread_id, &attr, thread_function, NULL);
    if (ret != 0) {
        printf("Thread creation failed!\n");
        return 1;
    }
    pthread_join(thread_id, NULL);  // 等待线程结束
    printf("Main thread is exiting...\n");
    pthread_attr_destroy(&attr);  // 销毁线程属性
    return 0;
}

运行结果:

在这个示例中,我们通过pthread_attr_setschedpolicy函数将线程的调度策略设置为SCHED_FIFO,并通过pthread_attr_setschedparam函数设置了线程的优先级。

五、总结

本文详细介绍了Linux中线程的基本概念和线程控制的相关知识,包括线程的创建与终止、线程属性、线程的取消与清理、线程的调度等内容。通过代码示例,读者可以更好地理解这些概念,并在实际编程中应用这些知识。

有关线程的一些基本概念我们可以通过下面的图片自行查看一下,比如线程与进程之间的地址空间分配问题,线程所拥有的独立的栈区是怎么一回事等

感谢各位大佬观看,创作不易,还请各位大佬点赞支持!!!

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

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

相关文章

深入探索 iOS 卡顿优化

认识卡顿 一些概念 FPS&#xff1a;Frames Per Second&#xff0c;表示每秒渲染的帧数&#xff0c;通过用于衡量画面的流畅度&#xff0c;数值越高则表示画面越流畅。CPU&#xff1a;负责对象的创建和销毁、对象属性的调整、布局计算、文本的计算和排版、图片的格式转换和解码…

# 基于 OpenCV 的选择题自动批改系统实现

在教育领域&#xff0c;选择题的批改工作通常较为繁琐且重复性高。为了提高批改效率&#xff0c;我们可以利用计算机视觉技术&#xff0c;通过 OpenCV 实现选择题的自动批改。本文将详细介绍如何使用 Python 和 OpenCV 实现一个简单的选择题自动批改系统。 1. 项目背景 选择题…

身份验证:区块链如何让用户掌控一切

在网上证明你自称的身份变得越来越复杂。由于日常生活的很多方面现在都在网上进行&#xff0c;保护你的数字身份比以往任何时候都更加重要。 我们可能都接受过安全培训&#xff0c;这些培训鼓励我们选择安全的密码、启用双因素身份验证或回答安全问题&#xff0c;例如“你祖母…

嵌入式硬件: GPIO与二极管基础知识详解

1. 前言 在嵌入式系统和硬件开发中&#xff0c;GPIO&#xff08;通用输入输出&#xff09;是至关重要的控制方式&#xff0c;而二极管作为基础电子元件&#xff0c;广泛应用于信号整流、保护电路等。本文将从基础原理出发&#xff0c;深入解析GPIO的输入输出模式&#xff0c;包…

游戏引擎学习第194天

为当天的活动做铺垫 正在进行游戏开发中的调试和视图功能开发。目标是增加一些新功能&#xff0c;使得在开发过程中能够有效地检查游戏行为。今天的重点是推进用户界面&#xff08;UI&#xff09;的开发&#xff0c;并且尝试在调试变量的管理上找到一个折中的解决方案。计划探…

js文字两端对齐

目录 一、问题 二、原因及解决方法 三、总结 一、问题 1.text-align: justify; 不就可以了吗&#xff1f;但是实际测试无效 二、原因及解决方法 1.原因&#xff1a;text-align只对非最后一行文字有效。只有一行文字时&#xff0c;text-align无效&#xff0c;要用text-alig…

HarmonyOS 介绍

HarmonyOS简介 随着万物互联时代的开启&#xff0c;应用的设备底座将从几十亿手机扩展到数百亿IoT设备。全新的全场景设备体验&#xff0c;正深入改变消费者的使用习惯。 同时应用开发者也面临设备底座从手机单设备到全场景多设备的转变&#xff0c;全场景多设备的全新底座&am…

每天一篇目标检测文献(六)——Part One

今天看的是《Object Detection with Deep Learning: A Review》 目录 一、摘要 1.1 原文 1.2 翻译 二、介绍 2.1 信息区域选择 2.2 特征提取 2.3 分类 三、深度学习的简要回顾 3.1 历史、诞生、衰落和繁荣 3.2 CNN架构和优势 一、摘要 1.1 原文 Due to object dete…

ESXI 安装及封装第三方驱动和在ESXI系统下安装驱动

ESXI 安装及封装第三方驱动和在ESXI系统下安装驱动 准备工作在线安装 Windows PowerShell离线安装 Windows PowerShell更新在线更新离线更新 下载 ESXi-Customizer-PS-v2.6.0.ps1安装Python安装pip安装相关插件 下载离线捆绑包下载对应的网卡驱动&#xff08;如果纯净版可以进去…

【12】Ajax的原理和解析

一、前言 二、什么是Ajax 三、Ajax的基本原理 3.1 发送请求 3.2 解析内容 3.3 渲染网页 3.4 总结 四、Ajax 分析 五、过滤请求-筛选所有Ajax请求 一、前言 当我们在用 requests 抓取页面的时候&#xff0c;得到的结果可能会和在浏览器中看到的不一样&a…

双塔模型2之如何选择正确的正负样本

双塔模型&#xff1a;正负样本 选对正负样本的作用 > 改进模型的结构 正样本 什么是正样本&#xff1f;答&#xff1a;曝光且有点击的 “用户-物品” 二元组 存在的问题&#xff1a;存在28法则&#xff0c;即少部分物品&#xff08;比如热门物品&#xff09;占大部分点击…

《八大排序算法》

相关概念 排序&#xff1a;使一串记录&#xff0c;按照其中某个或某些关键字的大小&#xff0c;递增或递减的排列起来。稳定性&#xff1a;它描述了在排序过程中&#xff0c;相等元素的相对顺序是否保持不变。假设在待排序的序列中&#xff0c;有两个元素a和b&#xff0c;它们…

零基础使用AI从0到1开发一个微信小程序

零基础使用AI从&#xff10;到&#xff11;开发一个微信小程序 准备操作记录 准备 想多尝试一些新的交互方式&#xff0c;但我没有相关的开发经验&#xff0c;html&#xff0c;JavaScript 等都不了解&#xff0c;看了一些使用AI做微信小程序的视频教程&#xff0c;觉得自己也行…

基于Spring Boot的社区互助平台的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

【Elasticsearch入门到落地】10、初始化RestClient

接上篇《9、hotel数据结构分析》 上一篇我们讲解了导入的宾馆数据库tb_hotel表结构的具体含义&#xff0c;并分析如何建立其索引库。本篇我们来正式进入链接Elasticsearch的Java代码的编写阶段&#xff0c;先进行RestClient的初始化。 RestClient的初始化分为三步&#xff0c;…

【AI大模型系列】DeepSeek V3的混合专家模型机制-MoE架构(八)

一、什么是MoE架构 MoE架构的核心思想是将输入数据分配给不同的专家子模型&#xff0c;然后将所有子模型的输出进行合并&#xff0c;以生成最终结果。这种分配可以根据输入数据的特征进行动态调整&#xff0c;确保每个专家处理其最擅长的数据类型或任务方面&#xff0c;从而实…

HTML5贪吃蛇游戏开发经验分享

HTML5贪吃蛇游戏开发经验分享 这里写目录标题 HTML5贪吃蛇游戏开发经验分享项目介绍技术栈核心功能实现1. 游戏初始化2. 蛇的移动控制3. 碰撞检测4. 食物生成 开发心得项目收获后续优化方向结语 项目介绍 在这个项目中&#xff0c;我使用HTML5 Canvas和原生JavaScript实现了一…

QSettings用法实战(相机配置文件的写入和读取)

很多情况&#xff0c;在做项目开发的时候&#xff0c;将参数独立出来是比较好的方法 例如&#xff1a;相机的曝光次数、曝光时长等参数&#xff0c;独立成ini文件&#xff0c;用户可以在外面修改即可生效&#xff0c;无需在动代码重新编译等工作 QSettings便可以实现该功能 内…

机器学习——集成学习框架(GBDT、XGBoost、LightGBM、CatBoost)、调参方法

一、集成学习框架 对训练样本较少的结构化数据领域&#xff0c;Boosting算法仍然是常用项 XGBoost、CatBoost和LightGBM都是以决策树为基础的集成学习框架 三个学习框架的发展是&#xff1a;XGBoost是在GBDT的基础上优化而来&#xff0c;CatBoost和LightGBM是在XGBoost的基础上…

[蓝桥杯 2023 省 A] 网络稳定性

题目来自DOTCPP&#xff1a; 思路&#xff1a; ①由于题目没有告诉我们成树形结构&#xff0c;可能成环。因此&#xff0c;我们要自己构建树。 ②本体我们通过kruskal重构树&#xff0c;按边权从大到小排序&#xff0c;那么查询的两个点的最近公共祖先权值就是答案。 ③在通…