第一章 前言
Questions
(1)程序为什么要被编译器编译之后才能运行?
(2)编译器是如何将C语言程序转化成可执行的机器码的?
(3)可执行文件中有哪些内容,它们是如何组织的?
(4)解释#include<stdio.h>
的作用,C语言库是什么?要如何实现?
(5)不同的编译器、硬件平台以及操作系统,编译同一源代码的结果是否相同?为什么?
(6)一个程序是如何运行的?(如何装载、从哪里执行、到哪里结束、结束之后又会发生什么)
(7)一个程序在没有操作系统的机器上如何才能运行?
(8)printf函数是如何实现的?
(9)程序在运行时,它在内存中的组成?
在学习完《程序员的自我修养》之后,对上述问题的回答。
线程
线程基础
可抢占线程与不可抢占线程:线程在时间片用尽之后,被操作系统剥夺继续执行的权利而进入就绪状态,这个过程称为抢占。在早期的操作系统中,线程是不可抢占的,只有运行的线程主动发出放弃执行的命令,才能让其他就绪态线程获得CPU。
线程安全
信号量、互斥量、临界区:信号量可以跨进程使用,允许一个或多个线程访问共享资源,可以被任意线程申请与释放;互斥量可以跨进程使用,资源在任何时刻最多被一个线程占用,但是只有获取了互斥量的线程可以释放互斥量;临界区作用于进程内部,临界区中的资源在任何时刻最多被一个线程占用。
可重入:一个函数在未执行完的情况下,由于外部因素或内部调用,又一次进入自身执行。一个函数称为可重入的,即该函数被重入后不会产生任何不良后果。需满足如下条件:
- 不使用任何(局部)静态或全局的非const变量;
- 不返回任何(局部)静态或全局的非const变量的指针;
- 仅依赖于调用方提供的参数;
- 不依赖任何单个资源的锁;
- 不调用任何不可重入的函数;
过度优化:编译器在优化时,为了提高效率而交换两条互不相关的指令的执行顺序。CPU的动态调度技术,在执行程序时为提高效率而交换两条指令的执行顺序。
为解决这些优化而导致的多线程错误。在代码中加入volatile关键字阻止过度优化,它可以做到两件事:(1)阻止编译器为了提高运行速度将一个变量缓存到寄存器而不写回;(2)阻止编译器调整volatile变量的指令顺序。
CPU提供barrier指令,一条barrier指令指令阻止CPU将该指令之前的指令交换到barrier,反之亦然。