Visual Studio 2012未實施線程安全靜態初始化的C++ 11標準(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm)。我有一個函數本地靜態,我需要保證將以線程安全的方式初始化。下面是在Visual Studio 2012 不線程安全:std :: atomic_flag靜態初始化線程在Visual Studio 2012中安全嗎?
struct MyClass
{
int a;
MyClass()
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
a = 5;
}
};
void foo()
{
static MyClass instance;
std::cout << instance.a << '\n';
}
int main()
{
std::thread a(foo);
std::thread b(foo);
a.join();
b.join();
system("pause");
}
上述程序的上的Visual Studio 2012的輸出將最有可能是:
0
5
我需要解決這個問題,我試圖找到一種方法來使用函數本地靜態只(沒有全局或類級別靜態)。
我最初的想法是使用互斥鎖,但它遭受了靜態初始化線程安全性的相同問題。如果我在foo中有一個靜態的st :: mutex,第二個線程可能會在它處於無效狀態時獲得互斥量的副本。
另一種選擇是添加std :: atomic_flag自旋鎖。問題是,在Visual Studio 2012中std :: atomic_flag初始化線程是否安全?
void foo()
{
// is this line thread safe?
static std::atomic_flag lock = ATOMIC_FLAG_INIT;
// spin lock before static construction
while (lock.test_and_set(std::memory_order_acquire));
// construct an instance of MyClass only once
static MyClass instance;
// end spin lock
lock.clear(std::memory_order_release);
// the following is not thread safe
std::cout << instance.a << '\n';
}
在上面的代碼中,是否有可能讓兩個線程都通過自旋鎖定,還是隻能保證其中一個會自動鎖定?不幸的是,我想不出一種簡單的方法來測試這一點,因爲我不能在atomic_flag初始化程序中加入一些東西來減慢它,就像我可以用一個類一樣。但是,我想確保我的程序不會在藍色月亮中崩潰,因爲我做出了一個無效的假設。
我對這個同樣的問題感到困惑。由於「函數本地靜態」是[static init order fiasco]的經典答案(http://www.parashift.com/c++-faq/static-init-order.html),VS讓我們非常緊張與此綁定! –
螺旋鎖守衛是我最終如何解決問題。一定要包括內存順序的東西,否則,由於編譯器/ CPU的內存重新排序,您仍然可能會出現競爭狀態!第一次初始化完成後,上面的代碼幾乎不會旋轉,因爲它在非常少的幾個週期內獲取並清除鎖定。如果這是一個性能關鍵的代碼片段,那麼可以使用非易失性布爾封裝來實現更好的效果,從而避免潛在的核心同步,從而將整個事件從假轉換爲真(從不爲真)。 –