2017-02-14 48 views
0

我有兩個問題。如何說std :: thread停止?

1)我想用無限循環啓動一些函數,像服務器一樣工作,並在單獨的線程中檢查消息。但是,我想在我想要時從父線程關閉它。我很困惑如何在這種情況下std::futurestd::condition_variable。或者是創建一些全局變量並將它從父線程更改爲true/false更好。
2)我想要這樣的東西。爲什麼這個例子在運行時崩潰?

#include <iostream> 
#include <chrono> 
#include <thread> 

#include <future> 

std::mutex mu; 
bool stopServer = false; 

bool serverFunction() 
{ 

    while (true) 
    { 
     // checking for messages... 
     // processing messages 

     std::this_thread::sleep_for(std::chrono::seconds(1)); 

     mu.lock(); 

     if (stopServer) 
      break; 

     mu.unlock(); 
    } 

    std::cout << "Exiting func..." << std::endl; 

    return true; 
} 

int main() 
{ 
    std::thread serverThread(serverFunction); 

    // some stuff 

    system("pause"); 

    mu.lock(); 

    stopServer = true; 

    mu.unlock(); 

    serverThread.join(); 
} 
+5

std :: atomic stopServer;'應該就夠了。 –

回答

4

在運行時爲什麼這樣一個例子崩潰?

當您離開線程的內部循環時,會將互斥鎖保持鎖定狀態,因此如果再次使用該互斥鎖,父線程可能永遠被阻塞。

您應該使用std::unique_lock或類似的東西來避免這樣的問題。

+0

那麼解決方案呢?這是一個好的嗎? – banana36

+0

我認爲這種情況並沒有出現,因爲互斥鎖只在主服務器和內部的服務器中獲得並釋放,只有在主服務器已經發生的情況下才會釋放。 – Skym0sh0

+0

@ banana36您的解決方案是可以的,但是 - 正如其中一位評論者指出的那樣 - 您應該使用std :: atomic變量。您使用的方法非常普遍。 –

1

您將鎖定互斥體。不要在999/1000的情況下手動鎖定互斥鎖。

在這種情況下,您可以使用std::unique_lock<std::mutex>創建一個RAII鎖定器,以避免此問題。只需在示波器中創建它,並將鎖定區域結束於示波器的末端。

{ 
    std::unique_lock<std::mutex> lock(mu); 
    stopServer = true; 
} 
main

{ 
    std::unique_lock<std::mutex> lock(mu); 
    if (stopServer) 
     break; 
    } 
serverFunction

現在在這種情況下,你的互斥量是毫無意義的。去掉它。將bool stopServer替換爲std::atomic<bool> stopServer,並從您的代碼中刪除對mutexmu的所有引用。

可以安全地從不同線程讀取/寫入原子變量。

但是,您的代碼仍在等待。處理服務器處理消息的正確方法是守護消息隊列的條件變量。然後通過在消息隊列中對停止服務器消息(或標誌)進行排隊來停止它。

這會導致一個服務器線程無法喚醒,並且幾乎無時無刻地旋轉。相反,它阻塞條件變量(帶有一些虛假的喚醒,但很少見),並且只有在有新消息或被告知關閉時才真正醒來。

template<class T> 
struct cross_thread_queue { 
    void push(T t) { 
    { 
     auto l = lock(); 
     data.push_back(std::move(t)); 
    } 
    cv.notify_one(); 
    } 
    boost::optional<T> pop() { 
    auto l = lock(); 
    cv.wait(l, [&]{ return halt || !data.empty(); }); 
    if (halt) return {}; 
    T r = data.front(); 
    data.pop_front(); 
    return std::move(r); // returning to optional<T>, so we'll explicitly `move` here. 
    } 
    void terminate() { 
    { 
     auto l = lock(); 
     data.clear(); 
     halt = true; 
    } 
    cv.notify_all(); 
    } 
private: 
    std::mutex m; 
    std::unique_lock<std::mutex> lock() { 
    return std::unique_lock<std::mutex>(m); 
    } 
    bool halt = false; 
    std::deque<T> data; 
    std::condition_variable cv; 
}; 

我們使用boost::optionalpop返回類型 - 如果隊列被暫停,彈出返回一個空可選。否則,它會阻塞,直到有數據。

您可以用任意類似的東西,甚至是第一個元素說明是否有任何東西要返回的東西,或std::unique_ptr<T>std::experimental::optional或其他無數種選擇來替換它。

cross_thread_queue<int> queue; 

bool serverFunction() 
{ 
    while (auto message = queue.pop()) { 
    // processing *message 
    std::cout << "Processing " << *message << std::endl; 
    } 

    std::cout << "Exiting func..." << std::endl; 

    return true; 
} 

int main() 
{ 
    std::thread serverThread(serverFunction); 

    // some stuff 
    queue.push(42); 

    system("pause"); 

    queue.terminate(); 

    serverThread.join(); 
} 

live example

相關問題