我想知道是否可以使用
char Flag;
代替
std::atomic_flag Flag;
我知道,一般而言,C ++基本类型不是原子/线程安全的(这就是std::atomic
存在的原因),但是我也知道char
的大小始终为1个字节。而且我无法想象单字节读/写不是线程安全的情况。
我也找不到关于char变量的线程安全性的任何信息。
考虑以下示例(Win32,Visual Studio 2015,发行版,禁用优化):
// Can be any integral type
using mytype_t = unsigned char;
#define VAL1 static_cast<mytype_t>(0x5555555555555555ULL)
#define VAL2 static_cast<mytype_t>(0xAAAAAAAAAAAAAAAAULL)
#define CYCLES (50 * 1000 * 1000)
void runtest_mytype()
{
// Just to stop checking thread
std::atomic_bool Stop = false;
const auto Started = ::GetTickCount64();
auto Val = VAL1;
std::thread threadCheck([&]()
{
// Checking values
while (!Stop)
{
const auto Val_ = Val;
if (VAL1 != Val_ && VAL2 != Val_)
std::cout << "Error! " << std::to_string(Val_) << std::endl;
}
});
std::thread thread1([&]()
{
for (auto I = 0; I < CYCLES; ++I)
Val = VAL1;
});
std::thread thread2([&]()
{
for (auto I = 0; I < CYCLES; ++I)
Val = VAL2;
});
thread1.join();
thread2.join();
std::cout << "mytype: finished in " << std::to_string(::GetTickCount64() - Started) << " ms" << std::endl;
Stop = true;
threadCheck.join();
}
void runtest_atomic_flag()
{
std::atomic_flag Flag;
const auto Started = ::GetTickCount64();
std::thread thread1([&]()
{
for (auto I = 0; I < CYCLES; ++I)
auto Val_ = Flag.test_and_set(std::memory_order_acquire);
});
std::thread thread2([&]()
{
for (auto I = 0; I < CYCLES; ++I)
Flag.clear(std::memory_order_release);
});
thread1.join();
thread2.join();
std::cout << "atomic_flag: finished in " << std::to_string(::GetTickCount64() - Started) << " ms" << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
runtest_mytype();
runtest_atomic_flag();
std::getchar();
return 0;
}
它输出类似这样的内容(在几次测试中,这些值没有太大变化):
mytype: finished in 312 ms
atomic_flag: finished in 1669 ms
因此,char
而不是atomic_flag
的运行速度显着提高,在某些情况下可以发挥作用。
但是我与std::atomiс_flag
的发明是徒劳的。
请帮我弄清楚。至少,当我仅使用Windows,仅使用Visual Studio并且不需要考虑兼容性时,我可以使用char
吗?
答案 0 :(得分:0)
原子变量的更改在其他线程中也可见。
使用char
时,其他线程可能看不到该修改(这就是为什么某些人错误地使用volatile
进行同步)。
顺便说一句,在不同步的情况下同时修改char
是UB。