深入 C 语言和程序运行原理
于航
PayPal 技术专家
21121 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
深入 C 语言和程序运行原理
15
15
1.0x
00:00/00:00
登录|注册

13|标准库:你需要了解的 C 并发编程基础知识有哪些?

CPU 密集型
IO 密集型
原子操作接口
线程控制接口
示例
定义
示例
定义
示例
定义
thrd_exit
tss_create
thrd_detach
thrd_join
thrd_create
共享进程资源
线程控制块 (TCB)
更细粒度的运行单元
进程控制块 (PCB)
包含运行时信息
运行实例
C11 提供了并发编程的标准接口
正确设计避免数据竞争和竞态条件
多线程可以利用多核 CPU
GNU C 标准库 (Glibc)
OpenMP 模型
POSIX 模型
C11 标准
适合多线程的应用类型
stdatomic.h
threads.h
指令重排
竞态条件
数据竞争
线程退出
线程本地存储
线程分离
等待线程
创建线程
线程
进程
总结
资源
思考题
C11 并发编程接口
并发编程问题
线程的基本控制
进程 vs 线程
C 并发编程基础知识

该思维导图由 AI 生成,仅供参考

你好,我是于航。
在构建高性能应用时,并发编程是我们经常采用的一种技巧。它通过在程序的运行进程内提供可控制粒度更细的“线程”,从而将程序的整体功能拆分为更小的独立任务单元,并以此来进一步利用多核 CPU 的运算资源。
对于 C11 标准之前的 C 语言来说,想要构建多线程应用,只能依赖于所在平台上的专有接口,比如 Unix 与类 Unix 平台上广泛使用的 POSIX 模型,以及后起之秀 OpenMP 模型等。这些模型提供的编程接口,以及所支持平台都有很大的不同。因此,对于那时的 C 语言来说,想要编写高可移植性的多线程应用,仍需要花费很大功夫。
而自 C11 标准后,C 语言为我们专门提供了一套通用的并发编程接口,你可以通过标准库头文件 threads.h 与 stdatomic.h 来使用它们。其中,threads.h 中包含有与线程控制、互斥量、条件变量,以及线程本地存储相关的接口;而 stdatomic.h 中则包含有与原子操作相关的接口。这些接口提供了多种不同方式,可用来避免多线程应用在运行过程中可能遇到的各类线程同步问题。
C11 标准的发布,理论上使构建可移植的多线程 C 应用成为可能,但现实情况却并非这样理想。各类 C 标准库对 C11 中并发编程接口的支持程度不同,比如 Glibc(GNU C 标准库)在其 2018 年中旬发布的 2.28 版本中,才将相关接口进行了较为完整的实现。这就导致了 C11 标准中的这些重要特性,至今(2022 年初)仍然没有得到较为广泛的应用。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

C语言并发编程是构建高性能应用的重要技术之一。C11标准为多线程应用提供了通用的并发编程接口,但实际应用中仍需注意不同C标准库对其支持程度的差异。文章介绍了进程与线程的区别,以及C代码中创建线程的基本控制方法。通过使用threads.h头文件提供的接口,可以实现对线程的创建、等待、阻塞、分离和重新调度等操作。此外,文章还提到了多线程应用中可能遇到的数据竞争、竞态条件和指令重排等问题。文章内容涵盖了C语言并发编程的基础知识和相关接口的基本使用方式,适合读者快速了解并发编程的概况。文章通过具体的代码示例和解释,深入浅出地介绍了数据竞争和竞态条件的概念,以及在多线程环境下可能出现的问题。读者可以从中了解到并发编程中常见的陷阱和注意事项,为自己的程序设计和优化提供参考。文章还提到了指令重排的问题,为读者展示了并发编程中的一些细节和隐患,帮助他们更全面地理解并发编程的复杂性。整体而言,本文通过生动的例子和清晰的解释,为读者呈现了C语言并发编程的重要概念和技术特点,对于想要深入了解并发编程的读者具有一定的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入 C 语言和程序运行原理》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(10)

  • 最新
  • 精选
  • =
    1. IO密集型的应用。因为CPU等待IO完成的时间很多,在等待的时间内,多线程可以让其他应用继续执行 2. 有多核CPU时的计算密集型应用。因为可以利用多核CPU并行的优势,来快速完成计算

    作者回复: 回答的很棒!

    2022-01-12
    8
  • 赵岩松
    对于PCB我一直有一个疑惑,在我的理解中这个概念是操作系统统一的一个抽象概念,同时据我所知Linux中存在两个进程相关的结构:`thread_info`和`task_struct`,那么PCB和这两个结构有没有对应关系呢?至于TCB是我今天第一次听到的一个概念,同样的这个概念与前面提到的两个Linux结构有对应关系吗?

    作者回复: 是的,其实 PCB 与 TCB 就是针对进程和线程的两个不同的抽象概念,具体实现是可以多种多样的。简单来讲,Linux 在实现中没有为进程和线程单独设置用于存放相关信息的数据结构,而是统一使用 task_struct 存储通用的任务信息,使用 thread_info 存放平台相关的信息。区分是不是线程就看不同 task_struct 对象之间有没有共享资源。即你可以认为在 Linux 中只有进程(PCB),没有独立的线程(TCB)。而相较于 Windows 和 Sun Solaris 等明确区分进程与线程的操作系统实现,Linux 的实现相对更加优雅。 — 参考自《Linux Kernel Development 3rd Edition》,基于 2.6 版本内核。

    2022-01-12
    8
  • Luke
    Windows的VC对于c11的threads支持不好,微软是希望大家在它平台上用c艹😂,如果头铁非要在Windows上写标准化的C语言程序,threads这块老师有什么替代方案吗?pthread? 一开始在Linux下gcc编译,提示找不到thrd_xx的符号,原来编译选项要从-lthreads改成-pthreads

    作者回复: Windows 我用的少,盲猜 pthread 可能好用一些 hhh

    2022-09-06归属地:江苏
    3
  •  焚心以火
    大家有遇到 fatal error: 'threads.h' file not found 是怎么解决的呢?

    作者回复: 大多数情况是由于编译器不支持 C11 的多线程特性,你可以通过检测宏常量 __STDC_NO_THREADS__ 来判断当前编译器是否支持 threads.h,然后仅在支持的情况下再 include。

    2022-02-09
    2
  • 烟徒
    现在 C11 的 threads.h 库支持不是特别完善,用 c11 来讲,省劲是省劲,。。。

    作者回复: 嗯是的,确实是这样,大部分情况还是 posix。

    2023-03-13归属地:北京
    1
  • 杰良
    老师好,指令重排的例子,试了十多次没出现打印 x 为 0 的情况。这里可能发生的先执行 y 变量的更新的原因会是什么呢?

    作者回复: 主要是由于 CPU 流水线在执行指令时的顺序不确定性。乱序执行的目的本身还是在于提高指令执行性能。比如通过合理安排执行顺序,减少指令执行之间的数据等待,等等。

    2022-10-26归属地:广东
    1
  • 小杰
    如果编译显示没有threads文件,有两种方法可以解决。1、使用pthread.h头文件,使用方式与threads一样,也有不同的地方,但是极少。2、使用ubuntu20.04,gcc+glibc都是支持threads.h的,编译时可能也会出现没有此文件的错误,因为缺少一些文件。具体希望大家动手去解决。 最后回答一下老师的问题,适合场景应该是高并发,比如大量消息队列的处理,可以使用多线程。可以不用去等待一个任务执行完毕,再去执行下一个任务,这样可以充分利用cpu

    作者回复: 赞👍🏻

    2022-05-07
    1
  • ppm
    请问一个进程里面长时间有多个线程 好不好

    作者回复: 可以再描述的具体点?

    2022-01-12
    4
    1
  • 漠博嵩
    cmake 说找不到。函数

    作者回复: 哪一个函数没找到?

    2022-05-28
  • ABC
    便可能出现这样一种情况:某个线程以原子形式,执行了代码的第 14 行语句,将金额累加到账户 A。而此时,调度器将执行流程转移给另一个线程。该线程在上一个线程还没有完成对账户 B 的扣减操作前,便直接使用未同步的值参与了下一次的转账操作。 这句话表述有问题,应该是: 便可能出现这样一种情况:某个线程以原子形式,执行了代码的第 14 行语句,将金额累加到账户 B。而此时,调度器将执行流程转移给另一个线程。该线程在上一个线程还没有完成对账户 A 的扣减操作前,便直接使用未同步的值参与了下一次的转账操作。
    2023-08-25归属地:北京
收起评论
显示
设置
留言
10
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部