news 2026/1/3 7:15:46

Linux 线程(POSIX)核心教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 线程(POSIX)核心教程

一、线程核心概论

1.1 基本定义

Linux 中,线程被称为 “轻量级进程(LWP,Light Weight Process)”,线程属于进程—— 一个进程可以包含多个线程,所有线程共享进程的资源(如内存空间、文件描述符、信号处理等),同时拥有独立的执行流。

1.2 核心作用

与进程一致,线程的核心价值是实现并发执行,尤其适合处理:

  • 耗时任务(如 IO 操作、网络通信);
  • 并行计算(如多核心数据处理);
  • 程序模块化拆分(如一个线程处理输入,一个线程处理输出)。

1.3 关键特征

维度核心描述
资源分配进程是系统最小的资源分配单位(如内存、CPU 时间片);线程是系统最小的执行单位
层级关系进程内的所有线程是平级关系,无父子之分;进程默认包含一个 “主线程”(main 函数对应的线程)
资源范围线程共享进程的全局资源(堆、全局变量、文件描述符),但拥有独立的栈区(默认 8MB)

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

特性线程进程
资源共享共享进程资源(堆、全局变量等),仅栈区独立资源完全独立(虚拟地址空间隔离)
稳定性一个线程崩溃会导致整个进程崩溃单个进程崩溃不影响其他进程
创建开销仅需开辟独立栈区(8MB),开销极低需创建完整虚拟地址空间(3GB),开销大
并发度高(切换成本低)低(切换需切换地址空间)
通信方式直接读写共享变量(需同步)需 IPC(管道、消息队列、共享内存等)

三、线程编程核心步骤(POSIX 标准)

Linux 线程编程遵循 POSIX 标准(pthread 库),核心流程为:创建多线程线程空间执行任务线程资源回收(线程退出后栈区默认不释放,需手动 / 自动回收)

3.1 线程相关命令(调试 / 监控)

1. 查看线程信息

bash

运行

# 查看线程的PID、PPID、LWP(轻量级进程ID)、状态、命令 ps -eLo pid,ppid,lwp,stat,comm # 更详细的线程信息(含线程ID、CPU占用等) ps -eLf
2. 辅助命令(路径控制)

线程 / 进程的工作路径控制依赖以下函数(常与线程任务结合):

c

运行

// 获取当前工作路径 char *getcwd(char *buf, size_t size); // 参数:buf-存储路径的数组;size-数组最大长度 // 返回值:成功返回buf指针,失败返回NULL // 切换工作路径 int chdir(const char *path); // 参数:path-目标路径(绝对/相对) // 返回值:成功0,失败-1

3.2 线程核心函数(POSIX)

1. 创建线程:pthread_create

c

运行

#include <pthread.h> int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
  • 功能:创建一个新线程,线程启动后执行start_routine函数;
  • 参数
    • thread:输出参数,存储新线程的 ID(需提前定义);
    • attr:线程属性(如栈大小、分离属性),默认传NULL(使用默认属性);
    • start_routine:线程的执行函数(回调函数),格式为void* 函数名(void*)
    • arg:传给回调函数的参数(void * 类型,可传递任意数据);
  • 返回值:成功返回 0,失败返回错误码(非 0)。
2. 获取当前线程 ID:pthread_self

c

运行

pthread_t pthread_self(void);
  • 功能:获取当前线程的 ID;
  • 返回值:当前线程 ID(类型为unsigned long int,打印用%lu)。
3. 线程退出:pthread_exit

c

运行

void pthread_exit(void *retval);
  • 功能:线程主动退出(替代 return,更适合线程场景);
  • 参数retval:线程退出的返回值(“临死遗言”),可被pthread_join获取;
  • 注意:主线程调用pthread_exit仅退出自身,不影响其他子线程。
4. 取消线程:pthread_cancel

c

运行

int pthread_cancel(pthread_t thread);
  • 功能:主动请求终止指定线程;
  • 参数thread:要取消的线程 ID;
  • 返回值:成功 0,失败非 0;
  • 注意:线程需处于 “可取消状态” 才会响应(默认可取消)。
5. 阻塞回收线程资源:pthread_join

c

运行

int pthread_join(pthread_t thread, void **retval);
  • 功能:阻塞等待指定线程退出,并回收其资源(栈区);
  • 参数
    • thread:要回收的线程 ID;
    • retval:输出参数,存储线程的退出返回值(对应pthread_exit的参数);
  • 返回值:成功 0,失败非 0;
  • 核心特点:若线程未退出,调用者会阻塞,直到线程结束。
6. 设置线程分离属性:pthread_detach

c

运行

int pthread_detach(pthread_t thread);
  • 功能:设置线程为 “分离属性”,线程退出后资源(栈区)由系统自动回收;
  • 参数thread:要设置的线程 ID(可传pthread_self()设置自身);
  • 返回值:成功 0,失败非 0;
  • 核心价值:无需调用pthread_join,避免僵尸线程(线程退出后资源未释放);
  • 注意:设置分离属性后,无法再调用pthread_join回收该线程。

四、线程编程实战示例

4.1 基础示例:创建线程 + 阻塞回收

c

运行

#include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h> // 线程执行函数 void* thread_func(void* arg) { char *msg = (char*)arg; printf("子线程ID:%lu,参数:%s\n", pthread_self(), msg); sleep(2); // 线程退出,返回值为"thread exit" pthread_exit((void*)"thread exit"); } int main() { pthread_t tid; int ret; void *retval; // 创建线程 ret = pthread_create(&tid, NULL, thread_func, (void*)"hello thread"); if (ret != 0) { perror("pthread_create failed"); exit(1); } printf("主线程ID:%lu,创建子线程ID:%lu\n", pthread_self(), tid); // 阻塞回收线程,获取返回值 ret = pthread_join(tid, &retval); if (ret != 0) { perror("pthread_join failed"); exit(1); } printf("子线程退出,返回值:%s\n", (char*)retval); return 0; }

4.2 编译 & 运行

bash

运行

# 编译(必须链接pthread库) gcc thread_demo.c -o thread_demo -lpthread # 运行 ./thread_demo

4.3 输出结果

plaintext

主线程ID:140709267896000,创建子线程ID:140709259507456 子线程ID:140709259507456,参数:hello thread 子线程退出,返回值:thread exit

4.4 分离属性示例

c

运行

#include <stdio.h> #include <pthread.h> #include <unistd.h> void* thread_func(void* arg) { // 设置自身为分离属性 pthread_detach(pthread_self()); printf("子线程ID:%lu,执行任务\n", pthread_self()); sleep(2); printf("子线程退出,资源自动回收\n"); pthread_exit(NULL); } int main() { pthread_t tid; pthread_create(&tid, NULL, thread_func, NULL); // 主线程等待3秒,确保子线程执行完成 sleep(3); printf("主线程退出\n"); return 0; }

五、线程编程核心注意事项

  1. 编译必须链接 pthread 库:pthread 是独立库,编译时需加-lpthread,否则报 “undefined reference to pthread_create”;
  2. 资源共享与同步:线程共享进程资源,多线程操作共享变量时需加互斥锁(pthread_mutex),避免数据竞争;
  3. 线程退出方式
    • 子线程可通过pthread_exit主动退出;
    • 主线程用pthread_exit仅退出自身,用exit会终止整个进程;
  4. 资源回收
    • 非分离线程必须调用pthread_join回收,否则会产生 “僵尸线程”;
    • 分离线程无需回收,系统自动释放资源;
  5. 线程安全:避免在多线程中使用非线程安全函数(如strtok),优先使用线程安全版本(如strtok_r)。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/16 20:16:52

10 个专科生降AIGC工具推荐,AI写作优化神器

10 个专科生降AIGC工具推荐&#xff0c;AI写作优化神器 论文写作的困境&#xff1a;时间、重复率与降重的三重挑战 对于专科生来说&#xff0c;论文写作从来不是一件轻松的事。从选题到文献综述&#xff0c;再到撰写和修改&#xff0c;每一个环节都充满了挑战。尤其是在任务书阶…

作者头像 李华
网站建设 2025/12/26 15:46:07

哈希加密:给数据按下“唯一指纹”的魔法

你有没有想过&#xff0c;为什么登录网站时系统总能“认出”你的密码&#xff0c;但即使网站管理员也看不到你的密码原文&#xff1f;为什么下载大型文件时&#xff0c;官方会提供一串“验证码”让你核对&#xff1f;这一切的背后&#xff0c;都归功于一项被称为哈希加密的技术…

作者头像 李华
网站建设 2025/12/18 7:50:35

【零基础学java】(小疑问和几个水算法题)

浅浅计算一下自己活了多久吧&#xff0c;哈哈。这里的重点&#xff0c;把字符串表示的出生日期这个字符串变成Date对象&#xff0c;再用get方法获取到毫秒值&#xff0c;JDK以前的时间类&#xff0c;都要先获取对应的毫秒值补充&#xff08;由此可见打好基础的重要性&#xff0…

作者头像 李华
网站建设 2025/12/18 2:48:56

Unity游戏开发问答:LobeChat成为程序员搭档

Unity游戏开发问答&#xff1a;LobeChat成为程序员搭档 在Unity项目开发中&#xff0c;一个常见的场景是&#xff1a;你正为某个协程没有按预期执行而头疼&#xff0c;翻遍官方文档和Stack Overflow却找不到匹配的案例。此时如果能有一位经验丰富的资深工程师坐在旁边&#xff…

作者头像 李华