P.S*_*.S. 3 c++ windows multithreading atomic
在共享文件中声明和定义结构.
Windows API创建的两个线程CreateThread()都可以看到它的实例:
struct info
{
std::atomic<bool> inUse;
string name;
};
info userStruct; //this guy shared between two threads
Run Code Online (Sandbox Code Playgroud)
线程1连续锁定/解锁以写入结构中的成员(测试的值相同):
while (1)
{
userStruct.inUse = true;
userStruct.name= "TEST";
userStruct.inUse = false;
}
Run Code Online (Sandbox Code Playgroud)
线程2 只是读取和打印,只有它碰巧解锁它
while (1)
{
while (! userStruct.inUse.load() )
{
printf("** %d, %s\n\n", userStruct.inUse.load(), userStruct.name.c_str());
Sleep(500); //slower reading
}
printf("In Use!\n");
}
Run Code Online (Sandbox Code Playgroud)
期待看到很多:
"正在使用!"
如果它进入,每次一次,解锁时:
"0,TEST"
..它确实如此.
但也看到:
" 1,测试"
如果原子布尔为1,我不希望看到它.
我究竟做错了什么?
您的代码不是线程安全的.原子是原子的.但if声明不是!
怎么了:
Thread 1 Thread 2 Comment
while (! userStruct.inUse.load() ) ---> InUse is false
==> continues loop
inUse = true
==> continues loop already started
printf(...)
Run Code Online (Sandbox Code Playgroud)
在最坏的情况下,由于数据竞争可能会有UB(一个线程2修改字符串,线程1在修改期间读取字符串).
由于您打算将原子用作锁,只需使用为此类同步设计的实际锁,使用std::mutexa std::lock_guard.
例如:
struct info
{
std::mutex access;
string name;
};
Run Code Online (Sandbox Code Playgroud)
第一个线程将是:
while (1)
{
std::lock_guard<std::mutex> lock(userStruct.access); // protected until next iteration
userStruct.name= "TEST";
}
Run Code Online (Sandbox Code Playgroud)
然后,第二个线程可以尝试以非阻塞方式访问互斥锁:
while (1)
{
{ // trying to lock the mutex
std::unique_lock<std::mutex> lock(userStruct.access, std::try_to_lock);
if(!lock.owns_lock()){ // if not successful do something else
std::cout << "No lock" <<std::endl;
}
else // if lock was successfull
{
std::cout << "Got access:" << userStruct.name <<std::endl;
}
} // at this stage, the lock is released.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
Run Code Online (Sandbox Code Playgroud)
你正在对原子变量执行2次distict加载以检查然后输出.值可以在负载之间变化.你的字符串变量也有数据竞争.
您可以使用std :: atomic_flag或互斥锁轻松修复它
struct info
{
std::atomic_flag inUse;
std::string name;
};
//writer
while (1)
{
if (!userStruct.inUse.test_and_set()) {
userStruct.name= "TEST";
userStruct.inUse.clear();
}
}
//reader
while (1)
{
if (!userStruct.inUse.test_and_set())
{
printf("** %s\n\n", userStruct.name.c_str());
userStruct.inUse.clear();
}
printf("In Use!\n");
}
Run Code Online (Sandbox Code Playgroud)
你无法检查atomic_flag中的值,因为检查锁的值几乎总是一个坏主意,因为值可以在你采取行动之前改变.