首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >正确检查线程中的bool标志

正确检查线程中的bool标志
EN

Stack Overflow用户
提问于 2022-07-10 14:18:50
回答 1查看 184关注 0票数 2

如何在类中检查bool变量以确保线程安全?

例如,在我的代码中:

代码语言:javascript
复制
// test.h

class Test {
    void threadFunc_run();
    void change(bool _set) { m_flag = _set; }

    ...
    bool m_flag;
};


// test.cpp

void Test::threadFunc_run()
{
    // called "Playing"
    while(m_flag == true) {
        for(int i = 0; i < 99999999 && m_flag; i++) {
            // do something .. 1
        }

        for(int i = 0; i < 111111111 && m_flag; i++) {
            // do something .. 2
        }
    }
}

一旦在外部代码中执行change(..)函数,我就会停止“播放”。

它还希望在操作for语句的过程中有效。

根据搜索,存在识别即时变化的变量,如原子变化或易失性变化。

如果不是立即,是否有更好的方法来使用普通的bool

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-10 15:05:47

实际上,同步线程安全需要的不仅仅是一个bool。您将需要一个状态、一个互斥和一个像这样的条件变量。该方法还允许快速反应从循环中停止。

代码语言:javascript
复制
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <future>
#include <mutex>

class Test
{
private:
    // having just a bool to check the state of your thread is NOT enough. 
    // your thread will have some intermediate states as well
    enum play_state_t
    {
        idle,           // initial state, not started yet (not scheduled by OS threadscheduler yet)
        playing,        // running and doing work
        stopping,       // request for stop is issued
        stopped         // thread has stopped (could also be checked by std::future synchronization).
    };

public:
    void play()
    {
        // start the play loop, the lambda is not guaranteed to have started
        // after the call returns (depends on threadscheduling of the underlying OS)
        // I use std::async since that has far superior synchronization with the calling thead
        // the returned future can be used to pass both values & exceptions back to it.
        m_play_future = std::async(std::launch::async, [this]
        {
            // give a signal the asynchronous function has really started
            set_state(play_state_t::playing);
            std::cout << "play started\n";

            // as long as state is playing keep doing the work
            while (get_state() == play_state_t::playing)
            {
                // loop to show we can break fast out of it when stop is called
                for (std::size_t i = 0; (i < 100l) && (get_state() == play_state_t::playing); ++i)
                {
                    std::cout << ".";
                    std::this_thread::sleep_for(std::chrono::milliseconds(200));
                }
            }

            set_state(play_state_t::stopped);
            std::cout << "play stopped.\n";
        });

        // avoid race conditions really wait for
        // trhead handling async to have started playing
        wait_for_state(play_state_t::playing);
    }

    void stop()
    {
        std::unique_lock<std::mutex> lock{ m_mtx }; // only wait on condition variable in lock
        if (m_state == play_state_t::playing)
        {
            std::cout << "\nrequest stop.\n";
            m_state = play_state_t::stopping;
            m_cv.wait(lock, [&] { return m_state == play_state_t::stopped; });
        }
    };

    ~Test()
    {
        stop();
    }

private:

    void set_state(const play_state_t state)
    {
        std::unique_lock<std::mutex> lock{ m_mtx }; // only wait on condition variable in lock
        m_state = state;
        m_cv.notify_all();              // let other threads that are wating on condition variable wakeup to check new state
    }

    play_state_t get_state() const
    {
        std::unique_lock<std::mutex> lock{ m_mtx }; // only wait on condition variable in lock
        return m_state;
    }

    void wait_for_state(const play_state_t state)
    {
        std::unique_lock<std::mutex> lock{ m_mtx };
        m_cv.wait(lock, [&] { return m_state == state; });
    }

    // for more info on condition variables 
    // see : https://www.modernescpp.com/index.php/c-core-guidelines-be-aware-of-the-traps-of-condition-variables

    mutable std::mutex m_mtx;
    std::condition_variable m_cv;       // a condition variable is not really a variable more a signal to threads to wakeup
    play_state_t m_state{ play_state_t::idle };
    std::future<void> m_play_future;
};


int main()
{
    Test test;
    test.play();
    std::this_thread::sleep_for(std::chrono::seconds(1));
    test.stop();

    return 0;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72929177

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档