【发布时间】:2011-06-03 04:50:00
【问题描述】:
在多线程程序中使用静态变量(尤其是在函数中)有什么问题?
谢谢。
【问题讨论】:
标签: c++ multithreading static
在多线程程序中使用静态变量(尤其是在函数中)有什么问题?
谢谢。
【问题讨论】:
标签: c++ multithreading static
初始化不是线程安全的。两个线程可以进入函数并且都可以初始化函数范围的静态变量。这不好。不知道结果可能是什么。
在 C++0x 中,函数范围静态变量的初始化将是线程安全的;调用该函数的第一个线程将初始化该变量,并且调用该函数的任何其他线程都需要阻塞,直到该初始化完成。
我认为目前没有任何编译器 + 标准库对完全实现 C++0x 并发内存模型以及线程支持和原子库。
【讨论】:
static int... 的代码的汇编输出
static int,则没有动态初始化,并且在首次输入函数之前初始化了对象。 (我不打算在这里写一篇关于静态初始化的许多复杂性的论文;有很多很多细节。我只想在这里介绍最有问题的情况。)
static。我认为你可以在 C++ 中这样做。
要随机选择一个说明性示例,请使用 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。
即便如此,我仍认为以这种方式使用它是一个糟糕的设计决定,原因与使用全局变量为何不好的原因类似。除此之外,它可以被认为是调用者而不是被调用者维护和提供这种状态的更干净的接口。然而,这些都是主观的论点。
【讨论】:
静态变量通常意味着您的函数的多次调用将共享一个状态,从而相互干扰。
通常你希望你的函数是自包含的;拥有他们工作的所有内容的本地副本,并且不与外界共享任何 bar 参数和返回值。 (如果你以某种方式思考,它无论如何都不是函数的一部分。)
考虑:
int add(int x, int y);
绝对是线程安全的 x 和 y 的本地副本。
void print(const char *text, Printer *printer);
很危险,外面的人可能正在用同一台打印机做某事,例如在上面调用另一个 print()。
void print(const char *text);
绝对是非线程安全的,保证两个并行调用使用同一台打印机。
当然,有一些方法可以保护对共享资源的访问(搜索关键字:mutex);这正是你的直觉。
在大多数情况下,对变量的非同步并行写入也是非线程安全的,读写也是如此。 (搜索关键字:synchronization、synchronization primitives [其中mutex 只是一个],还有atomicity/atomic operation 用于何时并行访问是安全的。)
【讨论】: