C++ 线程没有看到带锁的刷新值

C++ 线程没有看到带锁的刷新值,c++,multithreading,C++,Multithreading,如何强制线程查看共享变量的更新值?我认为互斥锁应该有帮助,但在下面的代码中,我看不到正确的行为: #include <thread> #include <vector> #include <chrono> #include <iostream> #include <mutex> using namespace std; mutex coutm; class Timer { public: Timer() :

如何强制线程查看共享变量的更新值?我认为互斥锁应该有帮助,但在下面的代码中,我看不到正确的行为:

#include <thread>
#include <vector>
#include <chrono>
#include <iostream>
#include <mutex>
using namespace std;

mutex coutm;

class Timer {
    public:
        Timer() : 
            m_start(chrono::high_resolution_clock::now()),
            m_elapsedTime (0) {}
        ~Timer() {};
        void start() {
            while (m_elapsedTime < 50) {
                unique_lock<mutex> timerLock{m_timerMutex};
                m_elapsedTime += chrono::duration_cast<chrono::milliseconds>(chrono::high_resolution_clock::now() - m_start).count();
                unique_lock<mutex> lck{coutm};
                cout << "Timer thread. New timer value = " << m_elapsedTime << endl; 
                this_thread::yield();
            }
            unique_lock<mutex> lck{coutm};
            cout << "Time = " << m_elapsedTime << ". Done!" << endl;
        }
        double getElapsedTime() { 
            return m_elapsedTime;
        }
    private:
        double m_elapsedTime;
        decltype(chrono::high_resolution_clock::now()) m_start;
    public:
        mutex m_timerMutex;
};

void dummyPrint(Timer& m) {
    unique_lock<mutex> timerLock{m.m_timerMutex};
    auto t = m.getElapsedTime();
    while (t < 50) {
        unique_lock<mutex> lck{coutm};
        cout << "Waiting... Time = " << t << endl;
        this_thread::yield();
    }
}

int main() {
    Timer t;
    thread timerThread {&Timer::start, std::ref(t)};
    thread t1{&dummyPrint, std::ref(t)};
    timerThread.join();
    t1.join();
    return 0;
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
互斥coutm;
班级计时器{
公众:
计时器():
m_start(时钟::高分辨率时钟::现在()),
m_elapsedTime(0){}
~Timer(){};
void start(){
而(m_elapsedTime<50){
唯一的_locktimerlock{m_timerMutex};
m_elapsedTime+=chrono::duration_cast(chrono::high_resolution_clock::now()-m_start).count();
唯一锁lck{coutm};
库特
仅仅因为您首先构建了
timerThread
,然后构建了
t1
,您无法保证
Timer::start
将首先在其执行线程中运行,而
dummyPrint
将第二次在其自己的执行线程中运行。它不仅必须首先开始执行,还必须锁定首先是互斥锁,以便您看到预期的结果。这也不能保证。这里唯一的保证是新的执行线程将在
std::thread
完全构造后的某个点进入线程函数。就是这样

无论出于什么原因,在您的特定C++实现中,<代码> DimyPrime>代码>执行线程首先将其动作组合在一起,锁定互斥体,并发现它尚未初始化,并且<代码> MyELAPSEDSETIME> <代码>仍然是0。这就是您所看到的行为。 当涉及到多个执行线程时,您几乎没有什么保证。如果您需要特定的行为,您需要自己强制执行。在这里,最简单的操作过程是添加一个单独的

bool
标志,以及一个指示
timerThread
完成初始化的条件变量。
timerThread
初始化所有内容,设置标志,并向条件变量发送信号。
main
在构建第二个
std::thread
之前,等待设置标志

注意:不要忽略条件变量。
收益率
不如正确使用条件变量可靠

仅仅因为您首先构建了
timerThread
,然后构建了
t1
,您无法保证
Timer::start
将首先在其执行线程中运行,而
dummyPrint
将第二次在其自己的执行线程中运行。它不仅必须首先开始执行,还必须锁定首先是互斥锁,以便您看到预期的结果。这也不能保证。这里唯一的保证是新的执行线程将在
std::thread
完全构造后的某个点进入线程函数。就是这样

无论出于什么原因,在您的特定C++实现中,<代码> DimyPrime>代码>执行线程首先将其动作组合在一起,锁定互斥体,并发现它尚未初始化,并且<代码> MyELAPSEDSETIME> <代码>仍然是0。这就是您所看到的行为。 当涉及到多个执行线程时,您几乎没有什么保证。如果您需要特定的行为,您需要自己强制执行。在这里,最简单的操作过程是添加一个单独的

bool
标志,以及一个指示
timerThread
完成初始化的条件变量。
timerThread
初始化所有内容,设置标志,并向条件变量发送信号。
main
在构建第二个
std::thread
之前,等待设置标志


注意,不要吝啬条件变量。
yield
不如正确使用条件变量可靠。

你的意思是在循环内刷新
t
的值吗?愚蠢的我!是的。那应该在循环内!谢谢。
Timer::start
没有保护它在lo中访问
m\u elapsedTime
操作条件或最终打印,并且
dummyPrint
直到函数结束才会释放锁。您可以使用
std::atomic m_elapsedTime;
来防止UB将其更改为这样:您的意思是刷新循环中
t
的值吗?我真蠢!是的。这应该在循环中!谢谢。
计时器::start
在循环条件或最终打印中不保护其对
m_elapsedTime
的访问,并且
dummyPrint
在函数结束前不会释放锁。您可以使用
std::atomic m_elapsedTime;
来防止它这样更改:
thread timerThread {&Timer::start, std::ref(t)};
thread t1{&dummyPrint, std::ref(t)};