C++中对共享数据的存取在并发条件下可能会引起data race的undifined行为,需要限制并发程序以某种特定的顺序执行,
有两种方式:使用mutex保护共享数据,原子操作:针对原子类型操作要不一步完成,要么不做,不可能出现操作一半被切换CPU,
这样防止由于多线程指令交叉执行带来的可能错误。非原子操作下,某个线程可能看见的是一个其它线程操作未完成的数据。
std::atomic:例子
class Test
{
public:
Test() = default;
void CThreadFunc()
{
for (int i = 0; i < 10000; ++i)
{
//std::lock_guard<std::mutex> lck(Test::m_s_ivalue_mutex); //m_iValue需要加锁才可正常工作
m_iValue++;
m_atomic_value++; //不加锁,也可正常工作
}
}
void Start()
{
std::vector<std::thread> threads;
for (int i = 0; i < 10; ++i)
{
threads.push_back(std::thread(&Test::CThreadFunc, this));
}
for (auto& th : threads)
{
if (th.joinable())
{
th.join();
}
}
std::cout << "m_iValue:" << m_iValue << ", m_atomic_value:" << m_atomic_value << std::endl;
}
private:
int m_iValue = 0;
std::atomic<int> m_atomic_value = 0; //sta::atomic<T> 原子操作,可以替换为atomic_int m_atomic_value(0); 该方法对bool、long,char等适用
static std::mutex m_s_ivalue_mutex;
};
atomic_flag:例子
//atomic_flag只支持两种操作,test-and-set 和 clear。
//test_and_set() 函数检查 std::atomic_flag 标志,如果 std::atomic_flag 之前没有被设置过,
//则设置 std::atomic_flag 的标志,并返回先前该 std::atomic_flag 对象是否被设置过,
//如果之前 std::atomic_flag 对象已被设置,则返回 true,否则返回 false。
//clear 清除标志
// using atomic_flag as a lock
#include <iostream> // std::cout
#include <atomic> // std::atomic_flag
#include <thread> // std::thread
#include <vector> // std::vector
#include <sstream> // std::stringstream
std::atomic_flag lock_stream = ATOMIC_FLAG_INIT; // 设置并,初始化为false
std::stringstream stream;
void append_number(int x) {
while (lock_stream.test_and_set()) {}
stream << "thread #" << x << '\n';
lock_stream.clear();
}
int main ()
{
std::vector<std::thread> threads;
for (int i=1; i<=10; ++i) threads.push_back(std::thread(append_number,i));
for (auto& th : threads) th.join();
std::cout << stream.str();
return 0;
}
Possible output (order of lines may vary):
thread #1
thread #2
thread #3
thread #4
thread #5
thread #6
thread #7
thread #8
thread #9
thread #10
来源:https://www.cnblogs.com/heimazaifei/p/12176678.html