《程序员自我修养》运行库

在这里插入图片描述
C语言运行库
一个C语言运行库大致包含了如下功能:
1. 启动与退出:包括入口函数及入口函数所依赖的其他函数等。
2. 标准函数:由C语言标准规定的C语言标准库所拥有的函数实现
3. I/O:I/O功能的封装和实现.
4. 堆:堆的封装和实现.
5. 语言实现:语言中一些特殊功能的实现。
6. 调试:实现调试功能的代码。

入口函数和程序初始化
运行的代码并不是main的第一行,而是某些别的代码,这些代码负责准备好main函数执行所需要的环境,并且负责调用main函数,这时候你才可以在main函数里放心大胆地写各种代码:申请内存、使用系统调用、触发异常、访问O。在main返回之后,它会记录main函数的返回值,调用 atexit注册的函数,然后结束进程。
运行这些代码的函数称为入口函数或入口点(Entry Point),视平台的不同而有不同的名字。程序的入口点实际上是一个程序的初始化和结束部分,它往往是运行库的一部分。一个典型的程序运行步骤大致如下:
1. 操作系统在创建进程后,把控制权交到了程序的入口,这个入口往往是运行库中的某个入口函数。
2. 入口函数对运行库和程序运行环境进行初始化,包括堆、I/O、线程、全局变量构造,等等。
3. 入口函数在完成初始化之后,调用main函数,正式开始执行程序主体部分。
4. main函数执行完毕以后,返回到入口函数,入口函数进行清理工作,包括全局变量析构、堆销毁、关闭O等,然后进行系统调用结束进程。

在运行时库里面有好一个已经定义如下的入口函数:
(1)mainCRTStartup(或 wmainCRTStartup) //使用 /SUBSYSTEM:CONSOLE 的应用程序
(2)WinMainCRTStartup(或 wWinMainCRTStartup)//使用 /SUBSYSTEM:WINDOWS 的应用程序
(3)_DllMainCRTStartup //调用 DllMain(如果存在),DllMain 必须用 __stdcall 来定义

在默认情况下,如果你的程序中使用的是main()或_main()函数,这连接器会将你的使用(1)中的函数连接到你的exe中;如果你的函数是以WinWain()函数开始的则连接器使用(2)中的函数连接进exe中;如果我们写的是DLL程序这连接进DLL的是(3)中的函数。

用我们写的程序最终生成的exe执行时,一开始执行的就是上面的函数之一,而不是我们程序所写的main或WinMain等。

I/o初始化:首先I/O初始化函数需要在用户空间中建立stdin、 stdout、 stderr及其对应的FILE结构,使得程序进入main之后可以直接使用 printf、 scanf等函数。

IO初始化主要进行了如下几个工作:
1. 建立打开文件表。
2. 如果能够继承自父进程,那么从父进程获取继承的句柄。
3. 初始化标准输入输出。
在1O初始化完成之后,所有的IO函数就都可以自由使用了。

线程的访问权限
线程的访问能力非常自由,它可以访问进程内存里的所有数据,甚至包括其他线程的堆栈(如果它知道其他线程的堆栈地址,然而这是很少见的情况),但实际运用中线程也拥有自己的私有存储空间,包括:
1. 栈(尽管并非完全无法被其他线程访问,但一般情况下仍然可以认为是私有的数据)
2. 线程局部存储(Thread Local Storage,TLS)线程局部存储是某些操作系统为线程单独提供的私有空间,但通常只具有很有限的尺寸。
3. ·寄存器(包括PC寄存器),寄存器是执行流的基本数据,因此为线程私有。
在这里插入图片描述
CRT改进
1. 加锁,在多线程版本的运行库中,线程不安全的函数内部都会自动地进行加锁,包括 malloc、 printf等,而异常处理的错误也早早就解决了。因此使用多线程版本的运行库时,即使在 malloc/new前后不进行加锁,也不会出现并发冲突。
2. 改进函数调用方式,C语言的运行库为了支持多线程特性,必须做出一些改进。一种改进的办法就是修改所有的线程不安全的函数的参数列表,改成某种线程安全的版本。
3. 使用TLS,TLS 即线程局部存储,多线程环境下,设置错误代码时将值设置到TLS 中,以免引起混乱。

Windows TLS的实现
对于 Windows系统来说,正常情况下一个全局变量或静态变量会被放到“data”或“bss”段中,但当我们使用declspec(thread)定义一个线程私有变量的时候,编译器会把这些变量放到PE文件的“tls”段中。当系统启动一个新的线程时,它会从进程的堆中分配一块足够大小的空间,然后把“tls”段中的内容复制到这块空间中,于是每个线程都有自己独立的一个“tls”副本所以对于用declspec(thread)定义的同一个变量,它们在不同线程中的地址都是不一样的。在Windows平台上,系统提供了 TIsAlloc、 TIsGet Value、 TIsSet Value,和 TIsFree这4个AP函数用于显式TLS变量的申请、取值、赋值和释放;Linux下相对应的库函数为 pthread库中的 pthreadkeycreate、 pthread getspecific、 pthread_setspecific, pthread_key_delete,

《程序员的自我修养》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值