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_exitpthread_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
相关推荐
xiaoshuaishuai81 小时前
C# AI实现PR处理、单元测试
开发语言·c#·log4j
C++、Java和Python的菜鸟1 小时前
第7章 Java高级技术
java·开发语言
LONGZHIQIN1 小时前
C#基础复习笔记
开发语言·笔记·c#
mounter6251 小时前
BPF 的进化史:从网络过滤器到 AI 时代的 Linux 核心引擎
linux·网络·人工智能·ebpf·linux kernel·kernel
可靠的仙人掌2 小时前
SAC(Soft Actor-Critic)算法底座
开发语言·算法·php
学逆向的2 小时前
汇编——数据存储模式
开发语言·汇编·网络安全
geovindu2 小时前
CSharp: Prototype Pattern
开发语言·后端·设计模式·.net·原型模式·创建型模式
天天进步20153 小时前
Python全栈项目--校园食堂点餐与推荐系统
开发语言·python
aaPIXa6223 小时前
C++模板元编程:编译期计算Fibonacci数列
java·开发语言·c++