linux学习笔记(20)线程

线程

进程:一个正在运行的程序
线程:进程内部的一条执行路径(序列)

进程与线程的区别

◼ 进程是资源分配的最小单位,线程是 CPU 调度的最小单位
◼ 进程有自己的独立地址空间,线程共享进程中的地址空间
◼ 进程的创建消耗资源大,线程的创建相对较小
◼ 进程的切换开销大,线程的切换开销相对较小

单线程(Single Thread)

程序只有一个线程,所有任务按顺序执行。同一时间只能做一件事,一个任务没完成,下一个任务就必须等待。
  • 任务是串行的。
  • 如果某个任务耗时很长(比如网络请求、大量计算),会阻塞整个程序。

多线程(Multi Thread)

程序中存在多个线程,可以 “同时” 执行多个任务(实际上是 CPU 快速切换执行,宏观上看是并行的)。
  • 可以将耗时任务放到后台线程执行,不会阻塞主线程。
  • 宏观上并行执行,提高程序响应速度。
  • 但线程切换会带来上下文切换开销

线程的实现方式

在操作系统中,线程的实现有以下三种方式:
内核级线程
用户级线程
组合级线程

内核级线程(KLT)

  • 定义:线程的创建、调度、销毁等都是由 操作系统内核 完成的。
  • 特点
    • 内核维护线程的控制结构(TCB - Thread Control Block)。
    • 线程切换需要进入内核态,有一定开销。
    • 一个线程阻塞不会影响其他线程(因为调度由内核负责)。
    • 可以利用多核 CPU 实现真正的并行。
  • 举例
    • Windows 的线程
    • Linux 的 pthread(默认情况下是内核线程)

用户级线程(ULT)

  • 定义:线程的创建、调度、销毁等由 用户态的线程库 完成,不依赖操作系统内核。
  • 特点
    • 线程切换不需要进入内核态,速度快。
    • 内核并不知道用户级线程的存在,只把整个进程看作一个线程。
    • 如果一个线程阻塞(比如 I/O),会导致整个进程阻塞。
    • 不能利用多核 CPU(因为内核只调度整个进程)。
  • 举例
    • POSIX 的 ucontext 库
    • 早期的 Java 绿色线程(Green Threads,在 JDK 1.2 之后改用内核线程)

组合级线程(Hybrid Thread)

  • 定义:结合内核级线程和用户级线程的优点。
  • 特点
    • 用户级线程由用户态库管理。
    • 多个用户级线程可以映射到几个内核级线程上执行。
    • 可以利用多核 CPU,同时减少线程切换开销。
    • 一个用户线程阻塞不会导致整个进程阻塞。
  • 举例
    • Solaris 操作系统
    • Windows 的纤程(Fiber)
    • Java 的线程池 + 操作系统线程结合

其他特殊方式

  • 协程(Coroutine)
    • 由程序员在代码中显式控制切换,属于用户态轻量级线程。
    • 切换开销极小,适合高并发 I/O 场景。
    • 例如 Python 的 asyncio、Go 的 goroutine。
  • 纤程(Fiber)
    • Windows 提供的一种用户级线程,切换由程序自身控制。
    • 比线程更轻量,但不能利用多核。
Linux 中线程的实现:
Linux 实现线程的机制非常独特。
从内核的角度来说,它并没有线程这个概念。Linux 把所有的线程都当做进程来实现。
内核并没有准备特别的调度算法或是定义特别的数据结构来表征线程。
相反,线程仅仅被视为一个与其他进程共享某些资源的进程。每个线程都拥有唯一隶属于自己的task_struct,所以在内核中,它看起来就像是一个普通的进程(只是线程和其他一些进程共享某些资源,如地址空间)。

三个核心线程函数

1. pthread_create() - 创建线程

int pthread_create(pthread_t *thread, NULL,void* (*start_routine)(void*), void* arg);
  • thread: 保存线程ID
  • NULL: 线程属性(通常用NULL)
  • start_routine: 线程要执行的函数
  • arg: 传给线程函数的参数

2. pthread_join() - 等待线程结束

pthread_join(thread_id, NULL);
// 等待指定线程结束,类似进程的wait()

3. pthread_exit() - 线程退出

pthread_exit(NULL);
// 线程自己退出

编译运行:
# 编译时要链接线程库
gcc -o thread_simple thread_simple.c -lpthread
./thread_simple
给线程传递参数
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
// 线程函数可以接收参数
void* worker(void* arg) {
    int thread_num = *(int*)arg;  // 转换参数类型
    printf("线程%d: 开始工作\n", thread_num);
    sleep(1);
    printf("线程%d: 完成工作\n", thread_num);
    return NULL;
}
int main() {
    pthread_t threads[3];
    int args[3] = {1, 2, 3};  // 每个线程的参数    
    printf("创建3个线程...\n");
    for (int i = 0; i < 3; i++) {
        pthread_create(&threads[i], NULL, worker, &args[i]);
    }
    printf("所有线程已创建,等待它们完成...\n");
    for (int i = 0; i < 3; i++) {
        pthread_join(threads[i], NULL);
    }
    printf("所有线程都完成了!\n");
    return 0;
}

线程的基本概念总结

  1. 线程共享内存 - 所有线程访问相同变量
  2. 并发执行 - 线程会交替运行
  3. 需要同步 - 共享数据时需要保护
  4. 创建开销小 - 比进程快很多
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值