Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 读写竞争条件会同时改变读写数据吗?_C++_Multithreading_Race Condition - Fatal编程技术网

C++ 读写竞争条件会同时改变读写数据吗?

C++ 读写竞争条件会同时改变读写数据吗?,c++,multithreading,race-condition,C++,Multithreading,Race Condition,例如,如果我有以下代码: SomeType obj; void GUIThread() { ... while (true) // Read and print the content of obj ... } void workerThread() { ... // Do some calculation and write the result into obj ... }

例如,如果我有以下代码:

SomeType obj;  

void GUIThread()  
{  
    ...  
    while (true)  
        // Read and print the content of obj  
    ...  
}  

void workerThread()  
{  
    ...  
    // Do some calculation and write the result into obj  
    ...  
}  
出于性能原因,我不能在
obj
上使用互斥或任何类似的东西,我也不需要
GUIThread
打印的内容的精确性(
obj
存储
workerThread
的运行计算结果,这可以被视为“运行总数”.GUIThread需要做的只是显示在
workerThread
中进行的计算的大致进度。我要确保的是
GUIThread
workerThread
之间的读写竞争条件不会改变存储在
obj
中的数据,也不会导致程序崩溃。这是真的吗

p.S.
SomeType
包含内置整数类型和
std::bitset
,但只有前者可以同时访问。
位集
不会被
GUIThread
触及

p.p.S.也许这有点离题……但我认为我可以将运行结果存储在
workerThread
中的缓存中,并且只在相对较长的时间段内更新实际保护的数据(通过原子性或互斥锁或其他方式)。为了实现这一点,我需要确保以下代码是否能按预期工作:

struct SomeOtherType  
{  
    int a, b, c, d;  // And other primitive types  
}  

std::atomic<SomeOtherType> data;  // Will this work?  
struct SomeOtherType
{  
int a,b,c,d;//和其他基本类型
}  
std::原子数据;//这样行吗?

我想知道这是否可以保护
SomeOtherType
,我认为它可以,因为
SomeOtherType

中只有基本类型严重依赖于共享数据类型。 在复杂数据类型中可能发生的情况是,在写入操作期间,对象会短暂失效(例如,分配新的内部缓冲区)

对于简单的数据类型,如整数、浮点数等,代码在大多数情况下不会崩溃,但没有保证。这些应该声明为
volatile
,以避免编译器将它们缓存在寄存器中。强制设置记忆障碍将提高结果的准确性

如果你只是检查一个布尔标志或类似的东西,你可以侥幸逃脱

如果obj是线程安全的,那么您也可以


我的建议是,当有疑问时,使用一个低开销的锁,如自旋锁。

据我所知,您的结构如下所示

struct Data {
    int one;
    int two;
    std::bitset<SomeType> three;
}
struct数据{
int-one;
int-2;
std::位集三;
}
如果不想对其使用任何类型的锁,可以尝试交换指向此结构的共享指针。检查编译器是否支持它,这是一个新功能

std::shared_ptr<Data> dataPointer;

void GUIThread()  
{  
    ...  
    while (true)  {
       auto ptr = std::atomic_load(&dataPointer);
       // Read and print the content of *ptr
    ...  
}  

void workerThread()  
{  
    ...  
   // Do some calculation
   auto newPtr = std::make_shared<Data>();
   // make the new result visible to the gui thread
   std::atomic_store(&dataPointer, newPtr);
}
std::共享的ptr数据指针;
void GUIThread()
{  
...  
while(true){
自动ptr=std::原子加载(&dataPointer);
//阅读并打印*ptr的内容
...  
}  
void workerThread()
{  
...  
//算算
auto newPtr=std::make_shared();
//使新结果对gui线程可见
std::原子_存储(&dataPointer,newPtr);
}
您所说的是“我正在用未定义的行为编写代码。它会做我想要的吗?”。唯一的答案是除了编译器编写器之外,没有人知道

看起来你的代码很可能会做你想做的事情,因为这似乎是实现编译器的最简单的方法。但是它很可能决定你的循环之外的任何东西都不能写入该变量,因为如果它这样做了,那将是一场数据竞争,因此标准没有说明它将做什么,然后决定用程序的该部分中的一个常量,因为它不能更改并重新使用该内存来存储另一个指针的值,因此您的另一个线程会将一个完全未连接的值设置为null,并在一小时后使程序崩溃。当然不太可能,但我可以看到它是如何发生的


未定义的行为就是-未定义。它实际上可以做任何事情。某些事情显然比其他事情更可能发生,但您真的想因为认为“未定义”而冒险格式化用户的磁盘吗不适用于您的程序,无论风险看起来有多小?

这取决于某种类型。这是什么?从表面上看,您肯定必须使用读写锁。作为线程之间的简单进度计数器交换的某种类型可能是。@JohnZwinck它是一个用户定义的结构,包含内置整数类型(
int
unsigned long-long
,等等)和
std::bitset
。我尝试将
bitset
的内容以二进制格式存储到文件中,使用
fout.write((const char*)(&bits),sizeof(bits));
将其读回另一个
bitset
,使用
fin.read((char*)(&bits2),sizeof(比特2)“<代码> > BITSET 的大小随<代码> t>代码>而变化,所以我猜想所有数据都存储在 BITSET 中,没有任何堆上或什么。@ ArunMu,但我不能负担得起……只要它不破坏程序或更改数据。我知道。‘代码不会崩溃’相信我,我已经看到足够多的代码严重崩溃,因为这种对
易失性的误解。
!实际上,内存屏障不是很必要,因为正如我提到的,我不需要太多显示的准确性。我只需要实际存储的准确性。除此之外,速度优先。我已经修复了是的,就像egur说的,spinlock可以用来复制数据和打印数据。spinlock不会引起上下文切换,而且比互斥量轻得多。谢谢你,但这仍然有一些开销。你可以这样做eaper使用原始原子指针而不是共享的\u ptr,但是您必须手动管理内存