C++ 带std::ref和线程的争用条件

C++ 带std::ref和线程的争用条件,c++,multithreading,c++11,C++,Multithreading,C++11,我试图通过std::ref将一些变量传递给一个线程来防止竞争条件,但不太确定如何做到这一点 我基本上有: #include <thread> #include <mutex> #include <vector> std::mutex mtx; float getXData(); float getYData(); void plot(std::vector<float> x, std::vector<float> y); void c

我试图通过std::ref将一些变量传递给一个线程来防止竞争条件,但不太确定如何做到这一点

我基本上有:

#include <thread>
#include <mutex>
#include <vector>

std::mutex mtx;
float getXData();
float getYData();
void plot(std::vector<float> x, std::vector<float> y);
void calculateMeasurements(bool& currentlyRunning, std::vector<float>& xMeasurements,
                           std::vector<float>& yMeasurements){
  while (true){
     xMeasurements.push_back(getXData());
     yMeasurements.push_back(getYData());
     ...
         if (someCondition){
             currentlyRunning=false;
             xMeasurements.clear();xMeasurements.push_back(0);
             yMeasurements.clear();yMeasurements.push_back(0);
             currentlyRunning=true;
         }
    }

}


int main(){
std::vector<float> xMeasurements;
std::vector<float> yMeasurements;
xMeasurements.push_back(0);
yMeasurements.push_back(0);
bool currentlyRunning{true};
auto thread = std::thread(calculateMeasurements, std::ref(currentlyRunning), 
              std::ref(xMeasurements), std::ref(yMeasurements));
while (true){
  ...
  mtx.lock();
    if(currentlyRunning==true && xMeasurements.size()==yMeasurements.size()){
         plot(xMeasurements,yMeasurements);
         }
    }
  mtx.unlock();
}
#包括
#包括
#包括
std::互斥mtx;
浮点getXData();
float getYData();
无效图(标准::矢量x,标准::矢量y);
无效计算测量(布尔和当前运行,标准::向量和X测量,
标准::矢量和Y测量){
while(true){
xMeasurements.push_back(getXData());
Y测量。向后推(getYData());
...
如果(某些条件){
currentlyRunning=false;
xMeasurements.clear();xMeasurements.push_back(0);
yMeasurements.clear();yMeasurements.push_back(0);
currentlyRunning=true;
}
}
}
int main(){
std::矢量X测量;
std::矢量测量;
X测量值。向后推_(0);
i测量。推回(0);
bool currentlyRunning{true};
自动线程=标准::线程(计算测量,标准::参考(当前运行),
标准::参考(X测量),标准::参考(Y测量);
while(true){
...
mtx.lock();
如果(currentlyRunning==true&&xMeasurements.size()==yMeasurements.size()){
绘图(X测量、Y测量);
}
}
mtx.unlock();
}
因此,本质上发生的是后台有一个线程将元素推回xMeasurements和yMeasurements,这也会偶尔将xMeasurements和yMeasurements重置为0中的一个元素。 函数图要求xMeasurements和Ymeasurements具有相同的大小

我认为std::mutex::lock使std::mutex::lock和std::mutex::unlock之间的所有变量只能由调用std::mutex::lock的线程编辑,直到它解锁为止,因此在这里它应该防止另一个线程更改currentlyRunning、xMeasurements和yMeasurements。然而,偶尔在测线图上出现故障(X测量、Y测量);因为xMeasurements.size()=yMeasurements.size()(因此plot会尝试在xMeasurements.push_back(getXData())和yMeasurements.push_back(getYData());之间读取它,如果我对互斥锁的工作方式正确的话,就不会发生这种情况,因为它会检查锁中的互斥锁是否大小相同),或者因为xMeasurements或yMeasurements为空而失败(如果我对互斥锁的工作方式的理解是正确的,那么就不应该发生互斥锁,因为它会检查锁中的currentlyRunning==true,并且只有当currentlyRunning==false时才可以为空)

如何正确防止另一个线程更改通过引用传递给它的变量


谢谢

std::mutex::lock不保护它和std::mutex::unlock之间的变量。将其视为保护代码段。您需要在每次访问和编辑由线程修改的全局数据结构时锁定和解锁。请确保在编辑xMeasurements时锁定当我使用线程编程时,我通常喜欢在每个全局结构中引入一个互斥锁,这可能会导致竞争条件,但在这里,您可以使用一个互斥锁

#include <thread>
#include <mutex>
#include <vector>

std::mutex mtx;
float getXData();
float getYData();
void plot(std::vector<float> x, std::vector<float> y);
void calculateMeasurements(bool& currentlyRunning, std::vector<float>& xMeasurements,
                           std::vector<float>& yMeasurements){
  while (true){
     std::lock_guard<std::mutex> lg(mtx);
     xMeasurements.push_back(getXData());
     yMeasurements.push_back(getYData());
     ...
         if (someCondition){
             currentlyRunning=false;
             xMeasurements.clear();xMeasurements.push_back(0);
             yMeasurements.clear();yMeasurements.push_back(0);
             currentlyRunning=true;
         }
    }

}


int main(){
std::vector<float> xMeasurements;
std::vector<float> yMeasurements;
xMeasurements.push_back(0);
yMeasurements.push_back(0);
bool currentlyRunning{true};
auto thread = std::thread(calculateMeasurements, std::ref(currentlyRunning), 
              std::ref(xMeasurements), std::ref(yMeasurements));
while (true){
  ...
    std::lock_guard<std::mutex> lg(mtx);
    if(currentlyRunning==true && xMeasurements.size()==yMeasurements.size()){
         plot(xMeasurements,yMeasurements);
         }
    }
}
#包括
#包括
#包括
std::互斥mtx;
浮点getXData();
float getYData();
无效图(标准::矢量x,标准::矢量y);
无效计算测量(布尔和当前运行,标准::向量和X测量,
标准::矢量和Y测量){
while(true){
标准:锁紧装置lg(mtx);
xMeasurements.push_back(getXData());
Y测量。向后推(getYData());
...
如果(某些条件){
currentlyRunning=false;
xMeasurements.clear();xMeasurements.push_back(0);
yMeasurements.clear();yMeasurements.push_back(0);
currentlyRunning=true;
}
}
}
int main(){
std::矢量X测量;
std::矢量测量;
X测量值。向后推_(0);
i测量。推回(0);
bool currentlyRunning{true};
自动线程=标准::线程(计算测量,标准::参考(当前运行),
标准::参考(X测量),标准::参考(Y测量);
while(true){
...
标准:锁紧装置lg(mtx);
如果(currentlyRunning==true&&xMeasurements.size()==yMeasurements.size()){
绘图(X测量、Y测量);
}
}
}

互斥锁只为锁定它的线程提供互斥。如果有人爬到墙上,在前门上加锁没有任何作用。谢谢你的帮助,我只是想确认一下我的理解,基本上你说的是,当你在一个部分调用mtx.lock()时,到达mtx.lock()的任何其他线程将一直等到第一个部分到达mtx.unlock()?准确地说。它将在mtx.lock()上暂停,直到原始线程调用mtx.unlock()。cplusplus.com将其描述为互斥锁是一种可锁定对象,设计用于在关键代码段需要独占访问时发出信号,防止具有相同保护的其他线程并发执行并访问相同的内存位置。"也就是说,它保护的是关键部分本身,而不是变量本身。非常感谢您提供的快速而清晰的帮助,我接受了这个答案。@johncuningham@JohnDoe备注:您的代码不是异常安全的。如果在锁止互斥体之后和锁止互斥体之前线程中发生崩溃,您将锁定互斥体永远。用于作用域锁定。@k.v.感谢您让我知道!我将更新答案以反映这一点