2017-06-14 76 views
0

這與this問題的第二個答案有關。使用`atomic_flag`變量停止線程

我的測試代碼如下。我試圖啓動一個線程,然後使其停止使用std::atomic_flag。然後線程應該輸出一些循環執行和總持續時間,然後停止。

std::atomic_flag keepRunning = ATOMIC_FLAG_INIT; 

void F() 
{ 
    keepRunning.test_and_set(); 
    long long unsigned count = 0; 
    const time_t start = time(nullptr); 
    while (keepRunning.test_and_set()) 
    { 
    std::cout << '.'; 
    ++count; 
    } 
    const time_t duration = time(nullptr) - start; 
    std::cout << count << '\t' << duration << std::endl; 
} 

int main() 
{ 
    std::thread t(F); 
    keepRunning.clear(); 
    t.join(); 
} 

的問題是,該線程不會停止

這是爲什麼?

  • 編譯:G ++(Ubuntu的4.8.4-2ubuntu1〜14.04.3)4.8.4
  • OS:MacOS的塞拉利昂版10.12.2主機上客戶機操作系統的Ubuntu 14.04
  • 編譯標誌 - 我試着-O0-O4,它沒有任何區別。
+0

@andrewrk - 你可以看看這個問題嗎? – HEKTO

回答

1

在您的F()中,您忽略了第一個keepRunning.test_and_set()的輸出。您嘗試初始化該標誌會導致聲明main()中的競賽。根據哪些語句首先運行,您可以獲得預期的行爲或忽略調用和永不結束的線程。

F()有機會運行時,該標誌應該已經用正確的值初始化了。移動,最初的test_and_set()main()防止種族:

std::atomic_flag keepRunning = ATOMIC_FLAG_INIT; 

void F() 
{ 
    long long unsigned count = 0; 
    const time_t start = time(nullptr); 
    while (keepRunning.test_and_set()) 
    { 
    std::cout << '.'; 
    ++count; 
    } 
    const time_t duration = time(nullptr) - start; 
    std::cout << count << '\t' << duration << std::endl; 
} 

int main() 
{ 
    keepRunning.test_and_set(); 
    std::thread t(F); 
    keepRunning.clear(); 
    t.join(); 
} 

現在的標誌是有效僅在主變()和F()僅「讀」。

1

它不會停止(大部分時間),因爲F中的循環可能永遠不會看到清除標誌。

假設創建thread需要一些時間,keepRunning.clear()main可能首先運行。 當F終於開始運行時,立即設置該值並進入一個永遠不會看到清除標誌的循環,因此永不退出。

不是初始化F中的標誌值,而是將其初始化爲true。然而,std::atomic_flag不允許你這樣做,因爲它的接口有限(這個設計是有意的,std::atomic_flag應該被用作其他原語的低級構建塊)。

你可以使用一個std::atomic<bool>,它初始化爲trueF刪除初始store(true)。出於演示目的,我在main中清除標誌之前添加了sleep_for語句。

std::atomic<bool> keepRunning{true}; 

void F() 
{ 
    long long unsigned count = 0; 
    const time_t start = time(nullptr); 
    while (keepRunning) 
    { 
    std::cout << '.'; 
    ++count; 
    } 
    const time_t duration = time(nullptr) - start; 
    std::cout << count << '\t' << duration << std::endl; 
} 

int main() 
{ 
    std::thread t(F); 
    std::this_thread::sleep_for(1s); // optional 
    keepRunning = false; 
    t.join(); 
}