簡體   English   中英

停止來自主線程的無限循環線程

[英]Stop infinite looping thread from main

我對線程還比較陌生,但我仍在學習最佳技術和C ++ 11線程庫。 現在,我正在實現一個無限循環的工作線程,執行一些工作。 理想情況下,主線程可能會不時地停止循環,以與工作線程正在生成的信息進行同步,然后再次啟動它。 我最初的想法是這樣的:

// Code run by worker thread
void thread() {
    while(run_) {
        // Do lots of work
    }
}
// Code run by main thread
void start() {
    if ( run_ ) return;
    run_ = true;
    // Start thread
}
void stop() {
    if ( !run_ ) return;
    run_ = false;
    // Join thread
}
// Somewhere else
volatile bool run_ = false;

我對此並不完全確定,因此我開始進行研究,結果發現,實際上同步並不是必需使用volatile,實際上它通常是有害的。 另外,我發現了這個答案 ,它描述的過程幾乎與我所描述的過程相同。 但是,在答案的評論中,此解決方案被描述為無效的,因為volatile不能保證不同的處理器內核能夠輕松地(如果有的話)傳達volatile值的變化。

我的問題是:我應該使用原子標志還是完全使用其他標志? 究竟什么是缺少揮發物的屬性,然后通過有效解決我的問題所需的任何構造提供了該屬性?

您是否正在尋找Mutex? 它們被制成為鎖定線程,以避免共享數據上的沖突。 您在找什么嗎?

我認為您想使用std :: mutex使用屏障同步

還可以看一下boost線程 ,以獲得相對高級的線程庫

從鏈接中查看以下代碼示例:

#include <iostream>
#include <map>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>

std::map<std::string, std::string> g_pages;
std::mutex g_pages_mutex;

void save_page(const std::string &url)
{
    // simulate a long page fetch
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::string result = "fake content";

    g_pages_mutex.lock();
    g_pages[url] = result;
    g_pages_mutex.unlock();
}

int main() 
{
    std::thread t1(save_page, "http://foo");
    std::thread t2(save_page, "http://bar");
    t1.join();
    t2.join();

    g_pages_mutex.lock(); // not necessary as the threads are joined, but good style
    for (const auto &pair : g_pages) {
        std::cout << pair.first << " => " << pair.second << '\n';
    }
    g_pages_mutex.unlock();
}

我建議使用std::mutexstd::condition_variable解決問題。 這是一個示例如何與C ++ 11一起工作的:

#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

using namespace std;

int main()
{
    mutex m;
    condition_variable cv;
    // Tells, if the worker should stop its work
    bool done = false;
    // Zero means, it can be filled by the worker thread.
    // Non-zero means, it can be consumed by the main thread.
    int result = 0;

    // run worker thread
    auto t = thread{ [&]{
        auto bound = 1000;
        for (;;) // ever
        {
            auto sum = 0;
            for ( auto i = 0; i != bound; ++i )
                sum += i;
            ++bound;
            auto lock = unique_lock<mutex>( m );
            // wait until we can safely write the result
            cv.wait( lock, [&]{ return result == 0; });
            // write the result
            result = sum;
            // wake up the consuming thread
            cv.notify_one();
            // exit the loop, if flag is set. This must be
            // done with mutex protection. Hence this is not
            // in the for-condition expression. 
            if ( done )
                break;
        }
    } };

    // the main threads loop
    for ( auto i = 0; i != 20; ++i )
    {
        auto r = 0;
        {
            // lock the mutex
            auto lock = unique_lock<mutex>( m );
            // wait until we can safely read the result
            cv.wait( lock, [&]{ return result != 0; } );
            // read the result
            r = result;
            // set result to zero so the worker can 
            // continue to produce new results. 
            result = 0;
            // wake up the producer
            cv.notify_one();
            // the lock is released here (the end of the scope)
        } 
        // do time consuming io at the side. 
        cout << r << endl;
    }

    // tell the worker to stop
    {
        auto lock = unique_lock<mutex>( m );
        result = 0;
        done = true;
        // again the lock is released here
    }

    // wait for the worker to finish.
    t.join();

    cout << "Finished." << endl;
}

通過本質上實現自旋鎖,您可以對std::atomic進行相同的操作。 自旋鎖的速度可能比互斥鎖慢。 因此,我在boost網站上重復了建議:

除非您確定自己了解后果,否則請勿使用自旋鎖。

我相信互斥量和條件變量是解決您的問題的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM