Lecture 6: Processes 3, Threads

回顾:

  1. 调度器类型:抢占式/非抢占式,长期/中期/短期)
  2. 性能评价标准
  3. 调度算法:FCFS, SJF,轮询,优先队列

本章小结:

  • 线程与进程
  • 不同的线程实现
  • POSIX线程(PThreads)

线程

从操作系统的角度看线程

一个进程由两个基本单元组成:
1. 资源:将所有相关资源分组在一起

  • 包含进程映像(程序、数据、堆、栈)的逻辑地址空间。
  • 文件,I/O设备,I/O通道,…

2. 执行轨迹,即一个被执行的实体

一个进程可以在多个执行轨迹之间共享其资源,即在同一资源环境中运行的多个线程

单线程进程(左),多线程进程(右)

每个线程都有自己的执行上下文(例如程序计数器,堆栈,寄存器)

所有线程都可以访问进程的共享资源

  • 例如文件,一个线程打开一个文件,同一进程的所有线程都可以访问该文件
  • 全局变量,内存等(⇒同步!)

与进程类似,线程具有:

  • 状态转换(新建、运行、阻塞、就绪、终止)(new, running, blocked, ready, terminated)
  • 线程控制块(TCB)
左边是共享资源,右边是私有资源

线程产生更少的创建/终止/切换开销(地址空间对于同一进程的线程保持相同)
一些cpu对多线程有直接的硬件支持:通常,每个内核最多可以提供8个硬件线程

线程间通信进程间通信更容易/更快(线程默认共享内存)
地址空间中不需要保护边界(线程是合作的,属于同一个用户,并且有一个共同的目标)
必须仔细考虑同步

为什么要使用线程

多个相关的活动应用于相同的资源,这些资源应该是可访问/共享的
进程通常包含多个阻塞任务

  • I/O操作(线程阻塞,中断标志完成)
  • 内存访问:页面错误导致阻塞

这些活动应并行/同时进行
应用实例:web服务器、制作程序、电子表格、文字处理器、处理大数据量

线程的操作系统实现

用户线程 User threads:多对一

线程管理(创建、销毁、调度、线程控制块操作)通过用户库用户空间中完成
进程在内核不知情的情况下维护运行时系统管理的线程表

  • 类似于过程表
  • 用于线程切换
  • 跟踪线程相关信息

优点:

  • 线程位于用户空间(即,不需要模式切换
  • 对线程调度程序的完全控制
  • 操作系统无关(线程可以在不支持它们的操作系统上运行)

缺点:

  • 阻塞系统调用会挂起整个进程(用户线程被映射到单个进程,由内核管理)
  • 没有真正的并行性(进程在单个CPU上调度)
  • 时钟中断是不存在的(即用户线程是非抢占的)
  • 页面错误导致进程阻塞 
User threads

内核线程 Kernel Threads:一对一

内核管理线程,用户应用程序通过API系统调用访问线程设施

  • 线程表在内核中,包含线程控制块(进程控制块的子集)
  • 如果一个线程阻塞,内核将从相同或不同的进程中选择线程

优点:

  • 真正的并行是可以实现的
  • 不需要运行期系统

频繁的模式切换会导致性能下降
Windows和Linux应用这种方法

Kernel threads

混合实现 Hybrid Implementations:多对多

用户线程被复用到内核线程上
内核看到并调度内核线程(数量有限)
用户应用程序看到用户线程并创建/调度这些线程(数量不受限制)

Kernel threads
性能对比: 用户线程vs内核线程vs进程

Null fork:创建、调度、运行和终止空进程/线程的开销
信号等待:同步线程的开销

比较,单位为µs
线程的实现对比

线程管理:库(Libraries)

线程库提供了一个API/接口来管理线程。(例如,创建、运行、销毁、同步等)
线程库可以实现:

  • 完全在用户空间中(即用户线程)
  • 基于系统调用,即依赖内核进行线程实现

线程API的例子包括POSIX的PThreads, Windows Threads和Java Threads

  • PThread规范可以作为用户线程或内核线程实现

POSIX Threads

也被称为Pthreads,是POSIX标准的一部分,定义了一套用于创建和操纵线程的API。 它为操作系统级线程提供了统一的接口,使得在多种UNIX-like系统上编写可移植的多线程程序成为可能。 Pthreads提供了一套丰富的API,包括创建线程、销毁线程、线程同步和线程通信等操作。 这些API在C语言中定义,因此对于使用C语言进行多线程编程的 开发者 来说非常方便。

POSIX 线程 (Pthread)

深入理解 POSIX 线程 (pthread):从基础到高级应用-优快云博客https://blog.youkuaiyun.com/yangyangyiyang_/article/details/146888003

POSIX 线程是一种任何人可以实现规范,即它定义了一组 API(函数调用,超过 60 个)及其功能作用。
PThreads 的核心功能包括:

PThread的例子

欲获取更详细的描述,请在命令行中使用“man function_name”命令。

这段C程序演示了如何使用POSIX线程(pthread)创建多个线程,每个线程打印自己的ID:

  1. 主线程创建10个子线程,每个线程接收自己的ID作为参数

  2. 每个子线程执行hello函数,打印自己的ID

  3. 主线程等待所有子线程结束

  4. 程序退出

#include语句:

  • pthread.h:提供多线程相关函数

  • stdio.h:标准输入输出

hello线程函数:

void* hello(void* arg) {
    printf("Hello from thread %d\n", *((int*)arg));
    return 0;
}
  • 线程的入口函数,参数和返回值都是void*

  • 将参数转换为int*后解引用获取线程ID

  • 打印线程ID后返回0

创建线程的循环:

for(int i = 0; i < THREADS; i++) {
    args[i] = i;  // 设置线程参数
    if(pthread_create(threads + i, NULL, hello, args + i)) {
        printf("Creating thread %d failed\n", i); 
        return -1;
    }
}
  • pthread_create参数:

    • 线程标识符的地址

    • 线程属性(这里为NULL表示默认)

    • 线程函数

    • 传递给线程函数的参数

  • 如果创建失败返回非零值,程序退出

等待线程结束的循环:

for(int i = 0; i < THREADS; i++)
    pthread_join(threads[i], NULL);
  • pthread_join等待指定线程结束

  • 第二个参数可以接收线程返回值(这里不需要设为NULL)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值