6)其他线程不安全函数:包括与信号相关的函数。
在不进行线程安全保护的情况下,自然的具有线程安全的函数有:
1)字符处理,包括isdigit、topper等
2)字符串处理函数,包括strlen、strcmp等
3)数学函数,包括sin、pow等
4)字符串转换函数,包括atoi、atof等
5)获取环境变量,包括getenv等
6)变长数组辅助函数
7)非局部跳转函数,包括setjmp和longjmp
在C++中,入口函数还需要在main函数的前后完成全局变量的构造和析构。
2.4.1 glibc全局构造和析构
在glibc的启动文件中存在“.init”和”.finit“段,这两个段中的代码会调用_init()和_finit(),这两个函数先于/后于main函数执行。
为了了解全局对象的构造细节,对程序的启动过程进行更深一步的研究是必须的。在_start传递进来的init函数指针究竟指向什么?通过对地址的跟踪,init实际指向了_libc_csu_init函数。例如:

这段代码调用了_init()函数。
沿着程序与操作系统交互的轨迹,我们从程序如何链接、如何使用运行库的实现机制,层层挖掘和剖析,现在已经到了用户层与内核层面的界限了,也就是常说的系统调用。系统调用时应用程序与操作系统内核之间的接口,它决定了应用程序是如何与内核打交道的。无论程序是直接进行系统调用,还是通过运行库,最终还是会到达系统调用这个层面上。
3.1.1 什么是系统调用
在现代操作系统里,程序运行的时候,本身是没有权利访问多少系统资源的。由于系统有限的资源有可能被多个不同的应用程序同时访问,因此,如果不加以保护,那么各个应用程序难免产生冲突。所以现代操作系统都将可能产生冲突的系统资源保护起来,阻止应用程序直接访问。这些系统资源包括文件、网络、IO、各种设备等。
此外,还有一些行为,应用程序不借助操作系统是无法办到的。例如,让程序等待一段时间,
int i;
for(i=0;i<1000000;++i)
这样实现等待,消耗了CPU资源,所以并不是好办法。
可见,没有操作系统的帮助,应用程序的执行可谓寸步难行。为了让应用程序有能力访问系统资源,也为了让程序借助操作系统做一些必须由操作系统支持的行为,每个操作系统都会提供一套接口,以供应用程序使用。这些接口往往通过中断来实现,比如Linux使用0x80号中断作为系统调用的入口。
系统调用作为一个接口,而且是非常重要的接口,它的定义将十分重要。因为所有的应用程序都依赖于系统调用,那么,首先系统调用必须有明确的定义,即每个调用的含义、参数、行为都需要有严格而清晰的定义,这样应用程序(运行库)才可以正确地使用它;其次它必须保持稳定和向后兼容。
3.1.2 Linux系统调用
在x86下,系统调用由0x80中断完成,各个通用寄存器用于传递参数,EAX寄存器用于表示系统调用的接口号,比如EAX=1表示退出进程(exit);EAX=2表示创建进程(fork);EAX=3表示读取文件或IO(read);EAX=4表示写文件或IO(write)等,每个系统调用都对应于内核源代码中的一个函数,它们都以sys_开头的,不然exit调用对应于sys_exit函数。当系统调用返回时,EAX又作为系统调用的返回值。
下图是部分系统调用:


3.1.3 系统调用的弊端
系统调用完成了应用程序和内核交流的工作,因此理论上只需要系统调用就可以完成一些程序,但是:
事实上,包括Linux,大部分操作系统的系统调用都有两个特点:
1)使用不便。操作系统提供的系统调用接口往往过于原始,程序员需要了解很多与操作系统相关的细节。如果没有很好的包装,使用起来很不方便。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-76057-7.html
你是美国佬的私生子吗
任何工业品都有设计使用寿命
放银行多少还有点收益