news 2026/2/18 23:37:35

Linux线程基础

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux线程基础

一、线程的核心概论

在 Linux 系统中,线程是轻量级的进程,它并非独立存在,而是隶属于某个进程。一个进程可以包含多个线程,这些线程共享进程的大部分资源(如代码段、数据段、打开的文件描述符等),同时拥有自己独立的执行上下文。

线程的核心作用和进程一致,都是为了实现并发执行,尤其适用于处理相对耗时的任务。比如在一个网络服务程序中,主线程负责监听客户端连接,子线程负责处理每个客户端的请求,这种多线程模型可以大幅提升程序的响应效率。

二、线程与进程的核心区别

理解线程的关键,是厘清它与进程的核心差异 —— 这也是线程所有特性的根源,具体可从以下维度对比:

维度进程线程
资源分配单位系统最小资源分配单位系统最小执行单位
资源归属拥有独立的 3GB 用户空间,资源完全独立共享所属进程资源,仅独立拥有 8MB 栈区
稳定性进程崩溃不影响其他进程,稳定性高单个线程崩溃会导致整个进程崩溃,稳定性低
创建开销需分配完整 3GB 空间,开销极大仅开辟 8MB 栈区,开销远低于进程
并发能力创建 / 切换开销大,并发度低创建 / 切换开销小,并发度远高于进程

2.1 资源共享与独立性

  • 进程:资源完全对立,每个进程拥有独立的地址空间、文件描述符、全局变量等,进程间无法直接访问彼此资源,需通过管道、共享内存等 IPC 机制通信。
  • 线程:同一进程内的线程共享绝大部分资源(代码段、数据段、堆区、全局变量、打开的文件等),仅栈区独立(每个线程有专属 8MB 栈区,存储局部变量和函数调用栈)。这种特性让线程间通信成本极低,但也要求编程时注意资源竞争问题。

2.2 稳定性差异

进程是操作系统独立的资源分配单元,一个进程的崩溃(如段错误)只会释放自身资源,不会影响其他进程;而线程共享进程的资源空间,若某个线程触发内存非法访问等错误,操作系统会终止整个进程,导致所有线程一同退出。

2.3 创建开销与并发度

  • 创建开销:新建进程需要完整分配 3GB 用户空间,涉及页表、资源拷贝等大量操作;新建线程仅需在进程已有空间内开辟 8MB 栈区,几乎无额外资源分配成本。
  • 并发度:线程的创建和上下文切换开销远小于进程,系统可同时调度成百上千个线程,而进程数量受限于内存和系统资源,因此线程的并发能力远高于进程。

2.4 执行与层级特性

补充说明线程的核心执行特征:

  • 进程中的所有线程为平级关系,无父子线程之分;每个进程默认包含一个主线程main函数运行在主线程中。
  • 进程是 “资源容器”,线程是容器内的 “执行流”—— 没有进程的资源支撑,线程无法独立存在;没有线程,进程只是一个静态的资源集合,无法执行任何逻辑。

三、Linux 下查看线程信息的命令

在 Linux 中,我们可以通过以下命令查看线程的运行状态,这对调试多线程程序非常有帮助:

  1. ps -eLo pid,ppid,lwp,stat,comm该命令可以查看系统中所有线程的关键信息,各字段含义如下:
    • pid:线程所属进程的 ID
    • ppid:进程的父进程 ID
    • lwp:线程的 ID(轻量级进程 ID)
    • stat:线程的运行状态
    • comm:线程对应的命令名称
  2. ps -eLf该命令会以更详细的格式列出所有线程的信息,包括线程的优先级、CPU 占用时间等。

四、POSIX 线程编程步骤与核心函数

Linux 下的线程编程遵循 POSIX 标准,对应的线程库为pthread,编程的核心步骤为:创建多线程 → 线程空间操作 → 线程资源回收。下面逐一介绍核心函数的使用方法,并为每个函数提供独立的可运行示例代码。

4.1 线程创建:pthread_create

函数说明
#include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
  • 功能:创建一个新的线程
  • 参数说明
    • thread:指向pthread_t类型变量的指针,用于存储新创建线程的 ID(由函数返回)。
    • attr:线程属性,一般设为NULL,表示使用默认属性。
    • start_routine:函数指针,指向线程的执行函数(回调函数),该函数的返回值和参数均为void*类型,是线程的核心执行逻辑。
    • arg:传递给回调函数start_routine的参数。
  • 返回值:成功返回 0;失败返回对应的错误码。
独立示例代码
#include <stdio.h> #include <pthread.h> #include <string.h> #include <unistd.h> // 线程执行函数 void *thread_func(void *arg) { char *msg = (char *)arg; printf("子线程ID:%lu,接收参数:%s\n", pthread_self(), msg); sleep(2); // 模拟线程执行耗时操作 printf("子线程执行完成\n"); return NULL; } int main() { pthread_t tid; char *msg = "Hello Thread"; // 创建线程 int ret = pthread_create(&tid, NULL, thread_func, msg); if (ret != 0) { printf("创建线程失败:%s\n", strerror(ret)); return -1; } printf("主线程:创建线程成功,线程ID:%lu\n", tid); sleep(3); // 主线程等待子线程执行完成 printf("主线程执行完成\n"); return 0; }
编译运行
gcc pthread_create_demo.c -o pthread_create_demo -lpthread ./pthread_create_demo

4.2 获取线程 ID:pthread_self

函数说明
#include <pthread.h> pthread_t pthread_self(void);
  • 功能:获取当前线程的 ID
  • 参数:无
  • 返回值:成功返回当前线程的 ID(类型为pthread_t,可通过%lu格式符打印);失败返回非 0 值。
独立示例代码
#include <stdio.h> #include <pthread.h> #include <unistd.h> void *thread_func(void *arg) { // 获取子线程ID pthread_t tid = pthread_self(); printf("子线程:自身ID = %lu\n", tid); return NULL; } int main() { pthread_t tid; // 创建线程 pthread_create(&tid, NULL, thread_func, NULL); // 获取主线程ID printf("主线程:自身ID = %lu\n", pthread_self()); printf("主线程:创建的子线程ID = %lu\n", tid); sleep(1); // 等待子线程执行 return 0; }
编译运行
gcc pthread_self_demo.c -o pthread_self_demo -lpthread ./pthread_self_demo

4.3 线程退出:pthread_exit

函数说明
#include <pthread.h> void pthread_exit(void *retval);
  • 功能:子线程自行退出
  • 参数retval:线程退出时的返回状态,可被后续的资源回收函数获取。
  • 返回值:无
独立示例代码
#include <stdio.h> #include <pthread.h> #include <unistd.h> void *thread_func(void *arg) { printf("子线程:开始执行,准备退出\n"); sleep(2); // 定义退出返回值 int *ret = (int *)malloc(sizeof(int)); *ret = 99; // 线程退出,传递返回值 pthread_exit((void *)ret); } int main() { pthread_t tid; void *ret_val; pthread_create(&tid, NULL, thread_func, NULL); // 等待子线程退出并回收资源 pthread_join(tid, &ret_val); printf("主线程:子线程退出,返回值 = %d\n", *(int *)ret_val); free(ret_val); // 释放子线程分配的内存 return 0; }
编译运行
gcc pthread_exit_demo.c -o pthread_exit_demo -lpthread ./pthread_exit_demo

4.4 线程取消:pthread_cancel

函数说明
#include <pthread.h> int pthread_cancel(pthread_t thread);
  • 功能:请求结束一个指定的线程
  • 参数thread:需要被取消的线程的 ID
  • 返回值:成功返回 0;失败返回非 0 值。
独立示例代码
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <string.h> void *thread_func(void *arg) { printf("子线程:开始执行,进入循环\n"); // 线程设置为可取消(默认状态) pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); // 设置取消类型为立即取消(接收到取消信号后立即退出) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); while (1) { sleep(1); printf("子线程:循环执行中...\n"); } return NULL; } int main() { pthread_t tid; pthread_create(&tid, NULL, thread_func, NULL); // 主线程等待3秒后取消子线程 sleep(3); int ret = pthread_cancel(tid); if (ret != 0) { printf("取消线程失败:%s\n", strerror(ret)); return -1; } printf("主线程:已发送取消线程的请求\n"); // 回收子线程资源 pthread_join(tid, NULL); printf("主线程:子线程已被取消并回收\n"); return 0; }
编译运行
gcc pthread_cancel_demo.c -o pthread_cancel_demo -lpthread ./pthread_cancel_demo

4.5 线程资源回收:pthread_joinvspthread_detach

线程退出后,其栈区等资源不会默认释放,必须通过特定方式回收。pthread_joinpthread_detach是两种核心回收方式,二者核心区别如下:

特性pthread_joinpthread_detach
执行方式阻塞式(等待目标线程退出后才返回)非阻塞式(设置属性后立即返回)
资源回收时机线程退出后,由调用方主动回收线程退出后,由系统自动回收
退出状态获取可通过retval获取线程退出状态无法获取线程退出状态
调用限制只能被一个线程调用,重复调用会报错仅需调用一次,线程退出后自动生效
适用场景需要获取线程执行结果、需同步等待线程结束无需获取线程结果、希望异步释放资源
4.5.1pthread_join(阻塞式回收)
函数说明
#include <pthread.h> int pthread_join(pthread_t thread, void **retval);
  • 功能:回收指定线程的资源,并获取线程的退出状态
  • 参数说明
    • thread:需要回收的子线程的 ID
    • retval:指向void*类型的指针,用于存储线程的退出状态(即pthread_exit传递的参数)
  • 返回值:成功返回 0;失败返回非 0 值。
独立示例代码
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <string.h> void *thread_func(void *arg) { int num = *(int *)arg; printf("子线程:接收参数 = %d,开始执行\n", num); sleep(3); // 模拟耗时操作 // 退出并返回计算结果 int *ret = malloc(sizeof(int)); *ret = num * 2; pthread_exit((void *)ret); } int main() { pthread_t tid; int arg = 10; void *ret_val; // 创建线程 int ret = pthread_create(&tid, NULL, thread_func, &arg); if (ret != 0) { printf("创建线程失败:%s\n", strerror(ret)); return -1; } printf("主线程:等待子线程执行完成...\n"); // 阻塞回收子线程,获取返回值 ret = pthread_join(tid, &ret_val); if (ret != 0) { printf("回收线程失败:%s\n", strerror(ret)); return -1; } printf("主线程:子线程回收成功,返回值 = %d\n", *(int *)ret_val); free(ret_val); // 释放内存 return 0; }
编译运行
gcc pthread_join_demo.c -o pthread_join_demo -lpthread ./pthread_join_demo
4.5.2pthread_detach(分离式回收)
函数说明
#include <pthread.h> int pthread_detach(pthread_t thread);
  • 功能:设置线程的分离属性
  • 参数thread:需要设置分离属性的线程的 ID(可以是当前线程,如pthread_detach(pthread_self())
  • 返回值:成功返回 0;失败返回非 0 值。
独立示例代码
#include <stdio.h> #include <pthread.h> #include <unistd.h> #include <string.h> void *thread_func(void *arg) { // 为当前线程设置分离属性 int ret = pthread_detach(pthread_self()); if (ret != 0) { printf("子线程:设置分离属性失败:%s\n", strerror(ret)); pthread_exit(NULL); } printf("子线程:已设置分离属性,开始执行\n"); sleep(2); printf("子线程:执行完成,即将退出(资源会被系统自动回收)\n"); pthread_exit(NULL); } int main() { pthread_t tid; // 创建线程 int ret = pthread_create(&tid, NULL, thread_func, NULL); if (ret != 0) { printf("创建线程失败:%s\n", strerror(ret)); return -1; } printf("主线程:创建分离线程成功,ID = %lu\n", tid); // 尝试join分离线程(会失败) ret = pthread_join(tid, NULL); if (ret != 0) { printf("主线程:尝试join分离线程失败(预期结果):%s\n", strerror(ret)); } // 主线程等待子线程执行完成 sleep(3); printf("主线程:程序执行结束\n"); return 0; }
编译运行
gcc pthread_detach_demo.c -o pthread_detach_demo -lpthread ./pthread_detach_demo

五、总结

线程作为 Linux 下的轻量级进程,凭借其低开销、高并发的特性,成为实现并发程序的重要工具。与进程相比,线程共享进程资源(仅栈区独立)、创建开销仅为开辟 8MB 栈区(进程需 3GB 空间)、并发度更高,但稳定性更弱 —— 单个线程崩溃会导致整个进程退出。

在 POSIX 线程编程中,每个核心函数都有明确的定位:

  • pthread_create是线程创建的入口,需指定执行函数和参数;
  • pthread_self用于获取线程自身 ID,便于调试和线程标识;
  • pthread_exit让线程主动退出并传递返回值,pthread_cancel可被动终止线程;
  • pthread_join(阻塞回收)适合需要获取线程执行结果的场景,pthread_detach(分离回收)适合无需同步等待的场景。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/11 15:36:43

IBM推出开源智能体CUGA 任务完成率超五成

IBM研究人员发布了一款名为CUGA的开源智能体&#xff0c;旨在实现复杂企业工作流程的自动化&#xff0c;根据不同任务类型&#xff0c;其准确完成率约为50%。CUGA是"可配置通用智能体"的缩写。根据其在AI平台HuggingFace上的介绍&#xff0c;该软件通过"多智能体…

作者头像 李华
网站建设 2026/2/6 2:55:13

Java毕设项目推荐-基于JavaWeb的家装一体化平台室内设计、装修施工、建材选购、软装搭配、后期维护于一体的专业化家装服务平台【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/2/8 16:09:04

Java毕设项目推荐-基于SpringBoot+Vue的汽配销售管理系统基于JavaWeb的汽配销售管理系统【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/2/10 13:33:09

PHP转Go必看!GoFrame框架详解+30分钟搭建CRUD API(附代码步骤)

最近贼有意思&#xff0c;发现了一个账号&#xff0c;专门发PHP转Go的帖子&#xff0c;哎呦喂&#xff0c;这不正是我3年前做的事情吗&#xff1f;哈哈。 尤其看到他写的安利GoFrame教程的文章&#xff0c;有点刺激到我了&#xff0c;一看他就没我用的多&#xff0c;用的溜&…

作者头像 李华
网站建设 2026/2/7 23:28:37

如何快速掌握Mermaid Live Editor:专业图表制作的终极指南

如何快速掌握Mermaid Live Editor&#xff1a;专业图表制作的终极指南 【免费下载链接】mermaid-live-editor Edit, preview and share mermaid charts/diagrams. New implementation of the live editor. 项目地址: https://gitcode.com/GitHub_Trending/me/mermaid-live-ed…

作者头像 李华