多线程编程指南

重新考虑全局变量

以前,大多数代码都是为单线程程序设计的。此代码设计特别适合于大多数从 C 程序调用的库例程。对于单线程代码,进行了以下隐含假设:

以下示例论述了由于这些假设而在多线程程序中引发的一些问题,以及如何处理这些问题。

传统的单线程 C 和 UNIX 通常会处理在系统调用中检测到的错误。系统调用可将任何内容作为函数值返回。例如,write() 返回已传输的字节数。但是,会保留值 -1 以表明出现了错误。因此,当系统调用返回 -1 时,即表明调用失败。


示例 9–1 全局变量和 errno

extern int errno;

...

if (write(file_desc, buffer, size) == -1) {

    /* the system call failed */

    fprintf(stderr, “something went wrong, “

        “error code = %d\n”, errno);

    exit(1);

}

...

错误代码将被置于全局变量 errno 中,而不是返回可能与正常返回值混淆的实际错误代码。系统调用失败时,可以查看 errno 以了解错误所在。

现在,请考虑在多线程环境中,当两个线程几乎同时失败而出现的错误不同时会发生的情况。两个线程都期望在 errno 中找到其错误代码,但 errno 的一个副本不能同时包含两个值。此全局变量方法不适用于多线程程序。

线程可通过概念上的新存储类来解决此问题:线程特定数据。此类存储似于全局存储。可从正在运行的线程的任何过程访问线程特定数据。但是,线程特定数据专门用于线程。当两个线程引用同名称的线程特定数据位置时,这些线程引用的是两个不同的存储区域。

因此,使用线程时,对 errno 的每个引用都是特定于线程的,因为每个线程都具有专用的 errno 副本。在此实现方案中,通过使 errno 成为可扩展到函数调用的宏来实现特定于线程的 errno 调用。