Linux 线程的创建

1. 引言

在操作系统中,进程(Process) 是资源分配的基本单位,但进程切换时涉及内存空间、文件描述符、寄存器等大量上下文保存与恢复,系统开销较大 。为了提升并发性能,现代操作系统引入了轻量级进程(Lightweight Process, LWP) ,也就是我们常说的线程(Thread)。

线程 是进程内的一个执行流,同一进程内的所有线程共享相同的地址空间、文件描述符、用户/组 ID 等资源,因此线程间的切换开销远小于进程切换。在 Linux 中,内核并不严格区分进程与线程,线程本质上就是共享大部分资源的进程。

2. 线程共享资源

一个进程中的多个线程共享以下资源:

  • 可执行的指令(代码段)
  • 静态数据(全局变量、静态变量)
  • 进程中打开的文件描述符
  • 当前工作目录
  • 用户 ID 与用户组 ID

这些共享资源使得线程间通信比进程间通信(IPC)更加高效,但也带来了同步与互斥的需求,以避免数据竞争。

3. 线程私有资源

每个线程拥有自己独立的执行上下文,私有资源包括:

  • 线程 ID(TID):唯一标识一个线程
  • 程序计数器(PC)及相关寄存器:记录当前执行位置
  • 堆栈:用于存放局部变量、函数调用链等
  • 错误号(errno):线程独立的错误状态
  • 优先级:调度优先级
  • 执行状态和属性:如是否可分离、栈大小等

4. Linux 线程库:pthread

Linux 系统下最常用的线程库是 POSIX 线程库(pthread),它提供了一套完整的线程操作 API:

  • 线程生命周期管理
    • 创建线程(pthread_create)
    • 回收线程(pthread_join)
    • 结束线程(pthread_exit、pthread_cancel)
  • 同步与互斥机制
    • 互斥锁(pthread_mutex_t)
    • 条件变量(pthread_cond_t)
    • 信号量(sem_t,需链接 -lpthread 或 -pthread)

5. 线程创建:pthread_create 详解

5.1 函数原型

c 复制代码
#include <pthread.h>

int pthread_create(pthread_t *thread,
                   const pthread_attr_t *attr,
                   void *(*routine)(void *),
                   void *arg);

5.2 参数说明

  • thread :指向 pthread_t 类型变量的指针,用于存储新线程的标识符。
  • attr :线程属性指针,可设置栈大小、调度策略等;传入 NULL 表示使用默认属性。
  • routine :线程入口函数,其类型必须为 void *(*)(void *),即接收一个 void* 参数并返回 void*。
  • arg :传递给 routine 的参数,类型为 void*,可传递任意类型数据的地址。

5.3 返回值

  • 成功时返回 0。
  • 失败时返回错误码 (非负整数),可通过 strerror 输出错误信息。

5.4 获取当前线程 ID

c 复制代码
pthread_t pthread_self(void);

该函数返回调用线程自身的线程 ID(TID)。

注意 :主进程退出时,它创建的所有线程也会随之退出。此外,线程创建需要一定的时间,如果主进程在创建线程后立即退出,新创建的线程可能来不及执行。因此,在实际编程中,通常需要让主进程等待线程完成(例如使用 pthread_join)或通过其他同步机制确保线程有机会执行。

6. 常见编译与链接错误

6.1 错误一:线程函数类型不匹配

报错信息示例(编译时):

复制代码
error: incompatible type for argument 3 of 'pthread_create'
expected 'void * (*)(void *)', but argument is of type 'int * (*)(char *)'

原因 :pthread_create 的第三个参数要求函数签名严格为 void* (*)(void*),如果自定义的线程函数返回类型或参数类型不匹配,就会报此错误。

解决方法:将线程函数强制转换为正确的类型。

c 复制代码
// 假设原函数为 int* testThread(char* arg);
pthread_create(&tid, NULL, (void* (*)(void*))testThread, NULL);

6.2 错误二:未定义引用 pthread_create(链接错误)

报错信息示例(链接时):

复制代码
createP_t.c:(.text+0x4b):对'pthread_create'未定义的引用
collect2: error: ld returned 1 exit status

原因 :编译器找到了 pthread_create 的声明(头文件 pthread.h),但链接时找不到其实现。这是因为 pthread 库是系统库,需要显式链接。

解决方法 :在编译命令末尾添加 -lpthread 或 -pthread 选项。

bash 复制代码
gcc -o my_program my_program.c -lpthread
# 或
gcc -o my_program my_program.c -pthread

-pthread 选项除了链接库外,还会定义必要的宏,推荐使用。

7. 完整示例:创建并运行一个线程

下面是一个简单的示例,演示如何创建线程并传递参数。

c 复制代码
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>

// 线程入口函数
void* thread_func(void* arg) {
    int* p_num = (int*)arg;
    printf("Thread started, received number: %d\n", *p_num);
    sleep(1);
    printf("Thread finished.\n");
    return NULL;
}

int main() {
    pthread_t tid;
    int num = 42;

    // 创建线程
    int ret = pthread_create(&tid, NULL, thread_func, &num);
    if (ret != 0) {
        fprintf(stderr, "Failed to create thread: %s\n", strerror(ret));
        return 1;
    }

    printf("Main thread: created thread with ID %lu\n", (unsigned long)tid);

    // 等待线程结束(线程回收)
    pthread_join(tid, NULL);

    printf("Main thread: all threads completed.\n");
    return 0;
}

编译与运行:

bash 复制代码
gcc -o thread_demo thread_demo.c -lpthread
./thread_demo
相关推荐
卡卡~~13 小时前
C++学习
开发语言·c++
John_Hui13 小时前
CentOS7安装Nginx
linux·服务器·nginx
qetfw13 小时前
Bash 基础:脚本执行、引号与命令替换验证
linux·开发语言·chrome·bash
怪力左手13 小时前
cuda-toolkit离线安装
linux·运维·人工智能
无人生还别怕14 小时前
如何搭建k8s服务(docker部署)
linux·运维·docker·云原生·容器·kubernetes·openanolisos
Lsetea14 小时前
curl下载HTTPS正文是乱码:--compressed与Content-Encoding分层排查
linux·http·https·ssl证书·curl
杜 硕14 小时前
从零开始的C++生活——第四讲
开发语言·c++·生活
云和数据.ChenGuang14 小时前
Python 集合(set)常用函数详解与实战案例
开发语言·python·深度学习·langchain
硅基手札14 小时前
操作系统设计思想系列 05 · RTOS 核心矛盾 — 资源受限 × 时间确定性的设计决策树
linux·mcu·架构·操作系统·嵌入式开发·rtos·设计思想
程序员-Benothing14 小时前
Linux磁盘管理教程:MBR、GPT、fdisk、parted分区实战
linux·运维·服务器