繁体   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