Linux线程深度解析:从基础到实践

Linux线程深度解析:从基础到实践

一、线程基础概念

1. 进程与线程定义

  • 进程:一个正在运行的程序,是操作系统资源分配的最小单位(拥有独立的地址空间、文件描述符等资源),状态包括就绪、运行、阻塞。
  • 线程:进程内部的一条执行路径,是CPU调度的最小单位。一个进程可包含多个线程,共享进程的地址空间、全局变量、打开的文件等资源。

2. 核心优势

  • 轻量化:线程创建和切换的开销远低于进程,适合高并发场景。
  • 资源共享:同一进程内的线程共享内存空间,数据交互无需跨进程通信(需注意同步问题)。

二、多线程编程核心接口

1. 关键头文件与库

  • 头文件pthread.h(POSIX线程库)
  • 编译选项:需链接 pthread 库,使用 -lpthread(如 gcc -o demo demo.c -lpthread

2. 线程创建:pthread_create

int pthread_create(pthread_t *thread,       // 输出参数,存储新线程IDconst pthread_attr_t *attr, // 线程属性(NULL表示默认属性)void *(*start_routine)(void *), // 线程入口函数void *arg                // 传递给入口函数的参数
);
  • 返回值:成功返回0,失败返回错误码(非0)。
  • 参数注意:传递局部变量地址时需注意生命周期(线程未启动时变量可能已销毁),推荐使用动态分配内存或值传递。

3. 线程退出:pthread_exit

void pthread_exit(void *retval); // retval为退出值,可被pthread_join获取
  • 区别于exitexit终止整个进程,pthread_exit仅终止当前线程。

4. 线程等待:pthread_join

int pthread_join(pthread_t thread,        // 待等待的线程IDvoid **retval            // 接收退出值的指针(可NULL)
);
  • 作用:阻塞主线程直到目标线程结束,回收线程资源(避免内存泄漏)。

三、多线程编程实践和常见问题

1. 单线程示例:主线程与子线程协作

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>void* thread_func(void *arg) {for (int i = 0; i < 3; i++) {printf("子线程运行: %d\n", i);sleep(1);}pthread_exit((void*)100); // 传递退出值
}int main() {pthread_t tid;void *ret;// 创建线程pthread_create(&tid, NULL, thread_func, NULL);// 等待线程结束pthread_join(tid, &ret);printf("子线程退出值: %d\n", (int)ret);return 0;
}

2. 多线程参数传递陷阱

错误示例:传递局部变量地址
void* print_index(void *arg) {int idx = *(int*)arg; // 危险!arg可能指向已销毁的局部变量printf("索引: %d\n", idx);return NULL;
}int main() {pthread_t tid[5];int i;for (i = 0; i < 5; i++) {pthread_create(&tid[i], NULL, print_index, &i); // 所有线程共享i的地址}// 结果:打印的索引可能重复或超过5(i在循环结束后为5)return 0;
}
正确做法:值传递或动态分配
// 方法1:传递值(适用于简单类型)
pthread_create(&tid[i], NULL, print_index, (void*)i); // 强制类型转换,直接传值// 方法2:动态分配内存(适用于复杂数据)
int *idx = malloc(sizeof(int));
*idx = i;
pthread_create(&tid[i], NULL, print_index, idx);

3. 数据竞争与同步问题

问题场景:多个线程操作全局变量
int counter = 0;
void* increment(void *arg) {for (int i = 0; i < 1000; i++) {counter++; // 非原子操作,可能导致结果错误}return NULL;
}// 运行结果:最终counter可能小于5000(线程间操作未同步)
解决方案:互斥锁(Mutex)
#include <pthread.h>
pthread_mutex_t mutex;void* safe_increment(void *arg) {pthread_mutex_lock(&mutex); // 加锁counter++;pthread_mutex_unlock(&mutex); // 解锁return NULL;
}int main() {pthread_mutex_init(&mutex, NULL); // 初始化互斥锁// 创建线程...pthread_mutex_destroy(&mutex); // 销毁锁return 0;
}

四、进程 vs 线程:核心区别对比

特性进程线程
资源分配独立地址空间、文件描述符等共享进程资源(地址空间、全局变量)
调度单位进程线程
创建开销高(需分配独立资源)低(仅创建栈和线程控制块)
切换开销高(需切换地址空间等)低(仅切换寄存器和栈指针)
数据共享需IPC(管道、共享内存等)直接共享(需同步机制)
健壮性进程崩溃不影响其他进程线程崩溃可能导致进程崩溃

五、Linux线程实现机制

1. 线程实现方式

  • 用户级线程:由用户空间库管理(如POSIX线程库),内核 unaware,调度由用户程序控制(缺点:一个线程阻塞会导致整个进程阻塞)。
  • 内核级线程:由内核直接调度(如Linux的轻量级进程LWP),支持并行执行(需多核CPU)。
  • Linux实现:采用轻量级进程(LWP),本质是内核中的进程,但共享父进程的地址空间。每个线程对应一个独立的task_struct,但mm_struct(内存描述符)指向同一地址空间。

2. 线程与进程的内核视角

  • 在Linux中,线程被视为“共享资源的进程”,通过clone系统调用创建(可共享内存、文件描述符等资源)。
  • 查看线程:ps -eLf(LWP列显示线程ID),或使用pthread_self()获取当前线程ID。

六、思考:线程数量限制与调优

1. 影响线程数量的因素

  1. 虚拟地址空间:每个线程默认栈大小(如8MB)限制总线程数(32位系统约512线程,64位系统可更大)。
  2. 系统限制:通过ulimit -a查看max user processes(默认约1024)。
  3. 硬件资源:CPU核心数决定并行度,内存大小限制同时运行的线程数。

2. 理论计算示例

// 假设进程虚拟地址空间4GB,单个线程栈1MB:
最大线程数 ≈ 4GB / 1MB = 4096 个线程(实际因系统开销会更低)

3. 调优建议

  • 减小栈大小:通过pthread_attr_setstacksize设置更小的栈(需谨慎,避免栈溢出)。
  • 动态创建销毁:使用线程池复用线程,避免频繁创建开销。
  • 监控工具:用tophtop监控线程状态,strace追踪系统调用。

七、总结

线程是Linux高并发编程的核心工具,理解其与进程的区别、接口使用及同步机制是关键。在实际开发中,需根据场景选择合适的并发模型(多进程/多线程/异步),并注意资源竞争、性能瓶颈等问题。通过合理设置线程属性和使用同步工具,可充分发挥多核CPU性能,实现高效的并行计算。

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

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

相关文章

php学习笔记(全面且适合新手)

以下是专为 PHP 7.4 初学者设计的全面学习文档&#xff0c;涵盖基础语法、细节语法和进阶语法&#xff0c;结合 PHP 7.4 新特性与实战案例&#xff0c;帮助系统掌握 PHP 开发&#xff1a; 为什么特地做7.4的笔记而不做8的&#xff1f;因为公司用的7.4&#xff0c;哈哈 一、基…

开源分布式数据库(TiDB)

TiDB是由PingCAP 开发的开源分布式数据库&#xff0c;兼容 MySQL 协议&#xff0c;集成了 HTAP&#xff08;混合事务和分析处理&#xff09;的能力&#xff0c;能够同时处理在线事务和实时分析任务。 2015 年&#xff0c;TiDB 在 GitHub 创建&#xff0c;2025 年&#xff0c;Ti…

SpringBoot+Mybatis通过自定义注解实现字段加密存储

&#x1f60a; 作者&#xff1a; 一恍过去 &#x1f496; 主页&#xff1a; https://blog.csdn.net/zhuocailing3390 &#x1f38a; 社区&#xff1a; Java技术栈交流 &#x1f389; 主题&#xff1a; SpringBootMybatis实现字段加密 ⏱️ 创作时间&#xff1a; 2025年04月…

Windows 10系统中找回MySQL 8的root密码

以下是 在Windows 10系统中找回MySQL 8的root密码 的详细步骤&#xff1a; 步骤1&#xff1a;停止MySQL服务 按 Win R 输入 services.msc&#xff0c;打开「服务」管理器。找到 MySQL80&#xff08;或其他自定义服务名&#xff09;&#xff0c;右键选择 停止。 步骤2&#xf…

【计网】互联网的组成

回顾&#xff1a; 互联网(Internet)&#xff1a;它是一个专有名词&#xff0c;是一个特定的互连网&#xff0c;它是指当下全球最大的、最开放的、由众多网络相互连接而形成的特定的的互连网&#xff0c;采用TCP/IP协议族作为通信规则。 一、互联网的组成部分 从互联网的工作方…

【vue3】黑马程序员前端Vue3小兔鲜电商项目【八】

黑马程序员前端Vue3小兔鲜电商项目【八】登录页面 登录页面的主要功能就是表单校验和登录登出业务。 账号密码 accountpasswordcdshi0080123456cdshi0081123456cdshi0082123456cdshi0083123456cdshi0084123456cdshi0085123456cdshi0086123456cdshi0087123456cdshi0088123456 …

C++学习:六个月从基础到就业——C++11/14:右值引用与移动语义

C学习&#xff1a;六个月从基础到就业——C11/14&#xff1a;右值引用与移动语义 本文是我C学习之旅系列的第三十九篇技术文章&#xff0c;也是第三阶段"现代C特性"的第一篇&#xff0c;主要介绍C11/14中引入的右值引用和移动语义。查看完整系列目录了解更多内容。 引…

基于Qlearning强化学习的电梯群控系统高效调度策略matlab仿真

目录 1.算法仿真效果 2.算法涉及理论知识概要 2.1 Q-learning强化学习原理 2.2 基于Q-learning的电梯群控系统建模 3.MATLAB核心程序 4.完整算法代码文件获得 1.算法仿真效果 matlab2022a仿真结果如下&#xff08;完整代码运行后无水印&#xff09;&#xff1a; 仿真操作…

31.软件时序控制方式抗干扰

软件时序控制方式扛干扰 1. 软件时序控制抗干扰的时间逻辑2. 应用案例 1. 软件时序控制抗干扰的时间逻辑 &#xff08;1&#xff09;将受软件控制的功能或软件检测到的状态一一罗列&#xff1b; &#xff08;2&#xff09;将其中的潜在干扰和敏感信号分开&#xff1b; &#x…

Ubuntu环境下使用uWSGI服务器【以flask应用部署为例】

0、前置内容说明 首先要知道WSGI是什么&#xff0c;关于WSGI服务器的介绍看这篇&#xff1a;WSGI&#xff08;Web Server Gateway Interface&#xff09;服务器 由于从Python 3.11开始限制了在系统级 Python 环境中使用 pip 安装第三方包&#xff0c;以避免与系统包管理器&am…

d3_v7绘制折线图

<!DOCTYPE html> <html><head><meta charsetutf-8><title>需求</title><script src"https://d3js.org/d3.v7.min.js"></script><style>* {margin: 0;padding: 0;}html, body {width: 100%;height: 100%;displ…

Hotspot分析(1):单细胞转录组识别信息基因(和基因模块)

这一期我们介绍一个常见的&#xff0c;高分文章引用很高的一个单细胞转录组分析工具Hotspot&#xff0c;它可针对单细胞转录组数据识别有意义基因或者基因module&#xff0c;类似于聚类模块。所谓的”informative "的基因是那些在给定度量中相邻的细胞之间以相似的方式表达…

爬虫准备前工作

1.Pycham的下载 网址&#xff1a;PyCharm: The only Python IDE you need 2.Python的下载 网址&#xff1a;python.org&#xff08;python3.9版本之后都可以&#xff09; 3.node.js的下载 网址&#xff1a;Node.js — 在任何地方运行 JavaScript&#xff08;版本使用18就可…

基于Springboot旅游网站系统【附源码】

基于Springboot旅游网站系统 效果如下&#xff1a; 系统登陆页面 系统主页面 景点信息推荐页面 路线详情页面 景点详情页面 确认下单页面 景点信息管理页面 旅游路线管理页面 研究背景 随着互联网技术普及与在线旅游消费习惯的深化&#xff0c;传统旅游服务模式面临效率低、…

利用KMP找出模式串在目标串中所有匹配位置的起始下标

问题关键&#xff1a;完成首次匹配之后需要继续进行模式匹配。 到这一步后&#xff0c;我们不能直接将j 0然后开始下一轮匹配&#xff0c;因为已经匹配过的部分&#xff08;蓝色部分&#xff09;中仍然可能存在与模式串重叠的子串&#xff1a; 解决办法&#xff1a; 找到蓝…

RR(Repeatable Read)级别如何防止幻读

在 MySQL 数据库事务隔离级别中&#xff0c;RR&#xff08;可重复读&#xff09; 通过 MVCC&#xff08;多版本并发控制&#xff09; 和 锁机制 的组合策略来避免幻读问题。 一、MVCC机制&#xff1a;快照读与版本控制 快照读&#xff08;Snapshot Read&#xff09; 每个事务启…

Android运行时ART加载类和方法的过程分析

目录 一,概述 二,ART运行时的入口 一,概述 既然ART运行时执行的都是翻译DEX字节码后得到的本地机器指令了&#xff0c;为什么还需要在OAT文件中包含DEX文件&#xff0c;并且将它加载到内存去呢&#xff1f;这是因为ART运行时提供了Java虚拟机接口&#xff0c;而要实现Java虚…

Javase 基础加强 —— 02 泛型

本系列为笔者学习Javase的课堂笔记&#xff0c;视频资源为B站黑马程序员出品的《黑马程序员JavaAI智能辅助编程全套视频教程&#xff0c;java零基础入门到大牛一套通关》&#xff0c;章节分布参考视频教程&#xff0c;为同样学习Javase系列课程的同学们提供参考。 01 认识泛型…

Oracle VirtualBox 在 macOS 上的详细安装步骤

Oracle VirtualBox 在 macOS 上的详细安装步骤 一、准备工作1. 系统要求2. 下载安装包二、安装 VirtualBox1. 挂载安装镜像2. 运行安装程序3. 处理安全限制(仅限首次安装)三、安装扩展包(增强功能)四、配置第一个虚拟机1. 创建新虚拟机2. 分配内存3. 创建虚拟硬盘4. 加载系…

RAGFlow 接入企业微信应用实现原理剖析与最佳实践

背景 近期有医美行业客户咨询我们智能客服产品&#xff0c;期望将自己企业的产品、服务以及报价信息以企微应用的方式给到客户进行体验互动&#xff0c;提升企业运营效率。关于企业微信对接&#xff0c;我们分享下最佳实践&#xff0c;抛砖引玉。效果图如下&#xff1a; 这里也…