Linux线程2.0-POSIX线程控制,线程底层与进程。

@bit::Shadow
✧(≖ ◡ ≖✿

目录

POSIX线程

线程控制必要的库链接-lpthread

第三方库的位置

phtread.h头文件

头文件位置

[线程监视ps -aL](#线程监视ps -aL)

示例

基本线程控制

创建等待分离

线程创建

[pthread_attr_t* attr的部分默认属性](#pthread_attr_t* attr的部分默认属性)

线程等待

当前线程终止

线程取消

取消和终止的对比

主线程与新线程的分离

线程底层

☆线程的逻辑图解

☆轻量级进程的图解


POSIX线程

POSIX线程通常简称为pthread(这也是几乎所有线程接口的前缀),是POSIX(可移植操作系统接口)标准定义的多线程API规范。为Linux/Unix等许多系统提供了统一的线程创建、管理和同步接口。

线程控制必要的库链接-lpthread

在涉及线程链接时 需要加以 "-lpthread" 用于链接第三方库。(这是线程控制的基础)

为什么需要链接,先前我们使用的为什么不需要呢?

因为编译器默认不会把libpthread.so拉进来所以需要手动指定,否则虽然在编译期不会报错但是在链接期会报"undeclare "的错误。

第三方库的位置

phtread.h头文件

pthread.h内涵盖了所有线程接口(如:phtread_create() phtread_join()),类型(如:pthread_t、pthread_mutex_t、pthread_cond_t )、常量(如:**PTHREAD_CREATE_JOINABLE**设置线程可被等待回收♻️)。

头文件位置

bash 复制代码
w@instance-qhw6x01g:~/e2026/June/6-22$ ls -al /usr/include/pthread.h 
-rw-r--r-- 1 root root 48376 May 26  2025 /usr/include/pthread.h

线程监视ps -aL

cpp 复制代码
#include<iostream>
#include<unistd.h>
void test1();void test2();void test3();void test4();void test5();
int main()
{
    test1();
    return 0;
}

void* routine1(void*)
{
    sleep(5);
    return nullptr;
}

void test1()
{
    //创建两个线程使得睡眠并 可检测
    pthread_t pd1,pd2;
    pthread_create(&pd1,nullptr,routine1,(void*)"空1");
    pthread_create(&pd2,nullptr,routine1,(void*)"空2");
    //wait
    pthread_join(pd1,nullptr);
    pthread_join(pd2,nullptr);
}

输出

PID:进程ID相同意味着隶属同一块进程。

LWP(Light Weight Process):"轻量级进程"作为CPU调度的ID------与用户级使用标识ID区分开。

|---------------|----------------------------------------------------------------------|
| PID | 进程 ID(Process ID)。同一进程下的所有线程,其 PID 相同。 |
| LWP | 轻量级进程 ID (Lightweight Process ID)。这是内核视角下的线程 ID,是每个线程的唯一标识符。 |
| TIME | 该线程累计占用的 CPU 时间。 |
| COMMAND | 线程所属的进程名(所有线程显示相同名称)。 |

示例

bash 复制代码
w@instance-qhw6x01g:~/e2026/June/6-22$ ps -aL
    PID     LWP TTY          TIME CMD
  11586   11586 pts/0    00:00:00 a.out
  11586   11588 pts/0    00:00:00 a.out
  11586   11589 pts/0    00:00:00 a.out
  11658   11658 pts/1    00:00:00 ps

基本线程控制

创建等待分离

线程创建

cpp 复制代码
int pthread_create(pthread_t* thread, \
                   const pthread_attr_t* attr, \
                   void*(*start_routine)(void*), void* arg);   
                       //create的末尾'e'不要落下!

pthread_t(unsigned long ) thread:输出型参数,输出线程ID。(栈下动态库的独立线程的独立分配区的起始地址)

const pthread_attr_t* attr:设置创建线程的属性(通常无需设置nullptr默认即可)。

void*(*start_routine)(void*):函数指针返回值参数均为void*。

void* arg:传递给第三个函数的参数。

成功返回0,失败错误码被设置。

pthread_attr_t* attr的部分默认属性

|----------|---------------------------|-------------------------------|
| 分离状态 | PTHREAD_CREATE_JOINABLE | 线程是可等待的(需要 pthread_join 回收) |
| 调度策略 | SCHED_OTHER | 分时调度策略(CFS,完全公平调度器) |
| 栈大小 | 通常 8 MB | 可用 ulimit -s 查看系统默认栈大小 |

各线程专属栈大小查询ulimit -s

cpp 复制代码
w@instance-qhw6x01g:~/e2026/June/6-22$ ulimit -s 
stack size                  (kbytes, -s) 8192

线程等待

cpp 复制代码
int pthread_join(pthread_t thread, void** retval);

等待目标新线程,并使用二级指针接受其一级指针返回值(void*类型)。(例如对线程名字的带出)

一次只能等待一个线程。

成功返回0,否则错误码被设置。

当前线程终止

pthread_exit(void* retval); // 适用于在线程的任何位置终止该线程并返回reval。

与return (void*)retval;等价。

cpp 复制代码
void pthread_exit(void* retval);

线程取消

cpp 复制代码
int pthread_cancel(pthread_t thread); 
//send a cancellation request to specilized thread process

参数:要取消的线程ID

成功返回0,失败返回错误码。

取消和终止的对比

"取消"本质是一种请求而"终止"则是指令。

对比维度 自然终止 (return) 主动终止 (pthread_exit) 被动终止 (pthread_cancel)
触发者 当前线程 当前线程 其他线程
响应时间 立即 立即 取决于取消状态(可能延迟)
返回值 自定义 自定义 固定PTHREAD_CANCELED
清理函数 栈自动展开,执行析构 执行 pthread_cleanup_push 执行 pthread_cleanup_push
资源回收 join 或自动回收 join 或自动回收 join 或自动回收
是否可被拦截 不可以(除非你自己写 return 前的逻辑) 不可以(线程自己决定退出) 可以(目标线程可通过设置取消状态拒绝)

主线程与新线程的分离

由于主线程常常需要等待接受新线程,这就占用了主线程资源。(新线程状态joinable)因此要线程分离(!joinable or detach)

cpp 复制代码
pthread_detach(pthread_t thread);

可配合pthread_t pthread_self(); // 获取当前线程的ID

线程底层

线程创建的底层本质就是调用了clone(),而使得线程拥有独立的栈,线程间可以直接访问各栈。

| 对比维度 | pthread_create() (创建线程) | fork() (创建进程) |
| 核心系统调用 | clone() | clone() |
| 关键 flags 标志 | CLONE_VM (共享内存空间) CLONE_FILES (共享文件描述符表) CLONE_FS (共享文件系统信息) CLONE_SIGHAND (共享信号处理函数表) CLONE_THREAD(加入同一线程组) | flags 中没有设置 CLONE_VMCLONE_FILESCLONE_FS 等共享标志 |
| 共享资源 | 与父进程共享虚拟内存地址空间、文件描述符、信号处理器等 | 资源隔离,仅继承父进程数据的一份拷贝 |

调度单位 线程,拥有独立的 TID ,但同属一个线程组,共享一个 TGID(即进程 ID) 进程,拥有独立的 PID

☆线程的逻辑图解

☆轻量级进程的图解

感谢支持,持续更新

欢迎关注