C ++:多线程程序中的静态变量

时间:2011-01-04 04:22:15

标签: c++ multithreading static

在多线程程序中使用静态变量(特别是在函数内)有什么问题?

感谢。

3 个答案:

答案 0 :(得分:28)

初始化不是线程安全的。两个线程可以进入该函数,并且两个线程都可以初始化函数范围的静态变量。这不好。没有人知道结果会是什么。

在C ++ 0x中,函数范围静态变量的初始化将是线程安全的;调用该函数的第一个线程将初始化该变量,并且调用该函数的任何其他线程将需要阻塞,直到该初始化完成。

我认为目前没有任何编译器+标准库对完全实现C ++ 0x并发内存模型以及线程支持和原子库。

答案 1 :(得分:21)

要随机选择一个说明性示例,请在C库中使用asctime之类的界面。原型看起来像这样:

 char *
 asctime(const struct tm *timeptr);

这隐式必须有一些全局缓冲区来存储返回的char*中的字符。实现这一目标的最常见和最简单的方法是:

 char *
 asctime(const struct tm *timeptr)
 {
    static char buf[MAX_SIZE];

    /* TODO: convert timeptr into string */

    return buf;
 }

这在多线程环境中完全被破坏,因为buf对于asctime()的每次调用都将处于相同的地址。如果两个线程同时调用asctime(),则存在覆盖彼此结果的风险。在asctime()的合同中隐含的是字符串的字符将一直存在,直到下一次调用asctime(),并发调用会打破这一点。

在此特定示例中,通过线程本地存储(__thread__declspec(thread))可以解决此特定问题。我相信这个想法使它成为thread_local关键字的C ++ 0x。

即便如此,我认为以这种方式使用它是一个糟糕的设计决定,原因类似于使用全局变量的原因。除此之外,它可以被认为是调用者维护和提供这种状态而不是被调用者的更清晰的接口。然而,这些是主观论点。

答案 2 :(得分:2)

静态变量通常意味着您的函数的多次调用将共享一个状态,从而相互干扰。

通常你希望你的功能是自包含的;拥有他们工作的所有内容的本地副本,并与外部世界条形参数和返回值无任何共享。 (如果你认为某种方式,那么无论如何都不是这个功能的一部分。)

考虑:

int add(int x, int y);

绝对是线程安全的x和y的本地副本。

void print(const char *text, Printer *printer);

危险,外面有人可能正在用同一台打印机做某事,例如在它上面调用另一个print()。

void print(const char *text);

绝对是非线程安全的,两个并行调用保证使用相同的打印机。

当然,有一些方法可以保护对共享资源的访问(搜索关键字:mutex);这就是你的直觉感受。

对变量的非同步并行写入在大多数情况下也是非线程安全的,读写也是如此。 (搜索关键字:synchronizationsynchronization primitives [其中mutex只有一个],atomicity / atomic operation用于并行访问是安全的。)