wordpress安装2个网站吗,网站关键词优化办法,网页设计学生作业模板,一站式服务工作总结什么是原子操作
原子操作#xff08;Atomic Operation#xff09;是指不可中断的操作#xff0c;即在多线程环境下#xff0c;当一个线程在执行原子操作时#xff0c;不会被其他线程的调度和中断所影响。这种操作在多线程编程中尤为重要#xff0c;因为它能保证操作的原…什么是原子操作
原子操作Atomic Operation是指不可中断的操作即在多线程环境下当一个线程在执行原子操作时不会被其他线程的调度和中断所影响。这种操作在多线程编程中尤为重要因为它能保证操作的原子性从而避免数据竞争和不一致。
原子操作的特性
原子性操作不可分割即不可中断。可见性操作完成后其他线程能立即看到结果。有序性编译器和处理器不会重排序原子操作。
c 原子操作的支持
在C中原子操作可以通过atomic库来实现。atomic库提供了一组模板类如std::atomicT其中T可以是整型、指针类型等。这些模板类提供了一系列成员函数如load(), store(), exchange(), compare_exchange_weak(), compare_exchange_strong()等以实现原子操作。
示例使用不适用原子操作和使用原子操作比对
示例我们创建二十个线程同时分别对同一个对象的成员变量m_aa(初值为0)做10000自增运算按照正常运算所有线程运行完成后对象的成员变量值应该是20*10000 200000.
不使用原子操作
#includeiostream
#includethread
#includevector
#includeatomic
class ThreadTsetAtomic
{
private:int m_aa;// std::atomicint m_aa;
public:void add(){ int b10000;while(b--){m_aa;}}ThreadTsetAtomic(const int a):m_aa(a){}void showValue(){std::coutm_aastd::endl;}
};void testFun(ThreadTsetAtomic* sub)
{sub-add();
}
int main()
{ ThreadTsetAtomic test1(0);std::vectorstd::thread threadVec;for(int i0;i20;i){ std::thread test(testFun,test1);threadVec.push_back(std::move(test));// threadVec.emplace_back(testFun,test1);}for (auto t : threadVec) { t.join(); } test1.showValue();return 0;
}编译运行 可以看到这里运行的结果是30799 和我们实际预期的200000值相差很大
使用原子操作
示例
#includeiostream
#includethread
#includevector
#includeatomic
class ThreadTsetAtomic
{
private:// int m_aa;std::atomicint m_aa; //原子整型变量m_aa
public:void add(){ int b10000;while(b--){m_aa;}}ThreadTsetAtomic(const int a):m_aa(a){}void showValue(){std::coutm_aastd::endl;}
};void testFun(ThreadTsetAtomic* sub)
{sub-add();
}
int main()
{ ThreadTsetAtomic test1(0);std::vectorstd::thread threadVec;for(int i0;i20;i){ std::thread test(testFun,test1);threadVec.push_back(std::move(test));// threadVec.emplace_back(testFun,test1);}for (auto t : threadVec) { t.join(); } test1.showValue();return 0;
}编译运行 运行结果为200000和我们预期的结果一致 为什么示例一中不使用原子操作运行的结果和我们预期的值相差这么大呢
示例
#includeiostreamint main()
{int a 0;a;return 0;
}
编译运行 我们查看想加的汇编代码
0x0000555555554745 11: addl $0x1,-0x4(%rbp) 这一句的实现 地址计算 首先CPU 将寄存器 %rbp 的值与偏移量 -0x4 相加得到内存地址 -0x4(%rbp)。 内存访问 CPU 访问计算得到的内存地址读取其中的值。这个值是存储在该内存位置中的数据可能是一个整数值。 加法操作 CPU 将从内存中读取的值与立即数 0x1 相加得到一个新的结果。 写回内存 最后CPU 将加法结果写回到内存地址 -0x4(%rbp) 所指向的内存位置中。这会覆盖原来的值更新为新的结果。
也就是这个过程并非原子操作因为涉及多个步骤其中可能会发生中断、上下文切换或其他并发操作。要确保该操作是原子的可能需要使用硬件支持的原子操作指令或锁来确保在多线程环境下的原子性。
结合上面示例不加原子操作分析也就是多线程运行时整形变量的自加不是原子操作的当一个线程的操作还未完成可能这时候cpu就进行了线程切换从而导致计数值不准。
补充
std::atomic API 加载Load和存储Store
T load(std::memory_order order std::memory_order_seq_cst) const noexcept;void store(T desired, std::memory_order order std::memory_order_seq_cst) noexcept;
这对函数允许加载和存储原子变量的值。load 函数会返回当前原子变量的值而 store 函数会将给定的值存储到原子变量中。
#include atomic
#include iostreamstd::atomicint value(0);int main() {value.store(10); // 存储值为 10 到原子变量int loaded_value value.load(); // 加载原子变量的值std::cout Loaded value: loaded_value std::endl;return 0;
}交换Exchange
T exchange(T desired, std::memory_order order std::memory_order_seq_cst) noexcept;
这个函数会原子地将给定的值存储到原子变量中并返回原子变量之前的值。
#include atomic
#include iostreamstd::atomicint value(0);int main() {int previous_value value.exchange(10); // 原子地将值 10 存储到原子变量并返回之前的值std::cout Previous value: previous_value std::endl;return 0;
}比较并交换Compare and Exchange
bool compare_exchange_weak(T expected, T desired, std::memory_order success, std::memory_order failure) noexcept;bool compare_exchange_strong(T expected, T desired, std::memory_order success, std::memory_order failure) noexcept;
这对函数尝试原子地将原子变量的值与期望值进行比较如果相等则将新值存储到原子变量中并返回 true否则返回 false。compare_exchange_weak 和 compare_exchange_strong 的区别在于当原子变量的值与期望值不同时compare_exchange_weak 可能会失败而 compare_exchange_strong 会循环直到操作成功。
#include atomic
#include iostreamstd::atomicint value(0);int main() {int expected 0;int desired 10;bool success value.compare_exchange_weak(expected, desired); // 尝试将值从 0 替换为 10if (success) {std::cout Exchange successful std::endl;} else {std::cout Exchange failed std::endl;}return 0;
}