1 重入问题
传统的UNIX没有太多考虑线程问题,库函数里过多使用了全局和静态数据,导致严重的线程重入问题。
1.1 –D_REENTRANT /-pthread和errno的重入问题。
所先UNIX的系统调用被设计为出错返回-1,把错误码放在errno中(更简单而直 接的方法应该是程序直接返回错误码,或者通过几个参数指针来返回)。由于线程 共享所有的数据区,而errno是一个全局的变量,这里产生了最糟糕的线程重入问 题。比如:
do {
bytes = recv(netfd, recvbuf, buflen, 0);
} while (bytes != -1 && errno != EINTR);
在上面的处理recv被信号打断的程序里。如果这时连接被关闭,此时errno应该不 等于EINTR,如果别的线程正好设置errno为EINTR,这时程序就可能进入死循环。 其它的错误码处理也可能进入不可预测的分支。
在线程需求刚开始时,很多方面技术和标准(TLS)还不够成熟,所以在 为 了 解决这个重入问题引入了一个解决方案,把errno定义为一个宏:
extern int *__errno_location (void);
#define errno (*__errno_location())
在上面的方案里,访问errno之前先调用__errno_location()函数,线程库提供这个
函数,不同线程返回各自errno的地址,从而解决这个重入问题。在编译时加
-D_REENTRANT就是启用上面的宏,避免errno重入。另外
-D_REENTRANT
还影响一些stdio的函数。在较高版本的gcc
代码:
public class Singleton { //私有化构造器 private Singleton(){ } //单例缓存者,惰性初始化,第一次使用时初始化 private static class InstanceHolder { private static final Singleton INSTANCE = new Singleton(); } //提供全局访问点 public static Singleton getInstance(){ return InstanceHolder.INSTANCE; } //提供一个计数器来验证一个ClassLoader一个实例 private int counter=0; }
首先私有化构造器,其次使用InstanceHolder静态内部类持有单例对象,这样可以得到惰性初始化好处。最后提供全局访问点getInstance.使得需要该单例实例的对象能够获取到。
格式: gcc [option] [filename]
-c 只编译生成.o文件
-o output_filename
-O 优化程序
-O2 优化程度更深
-g 产生代码调试信息
-Wall 所有警告
-w 不产生任何警告
-DMACRO 相当于#define MACRO
-I dirname (大写的i)用" "的头文件若在当前目录没有,则到dirname中找
-L dirname 首先到dirname中寻找所需库文件(默认在预设路径找,如/usr/lib)
-lname 在连接时装载名字为"libname.a"的函数库
如: -lm 表示连接系统的数学库libm.a,
所有与浮点运算相关的都必须用数学库!
-static 库分动态和静态,动态通常以.so为后缀,静态通常以.a为后缀
静态库: 把用到的函数放在程序里,
动态库: 在程序内留下标记,当程序执行是先载入这个库
linux下进行连接的缺省操作是首先连接动态库
分段编译:
程序编译的流程:
相关选项:
-E 预编译,生成**.i
-S 汇编, 生成.s
-c 编译, 生成.o