成都网站建设哪家好文章,投资者关系互动平台,如何做网站聚合页,wordpress完整备份简介#xff1a; CSDN博客专家#xff0c;专注Android/Linux系统#xff0c;分享多mic语音方案、音视频、编解码等技术#xff0c;与大家一起成长#xff01; 优质专栏#xff1a;Audio工程师进阶系列【原创干货持续更新中……】#x1f680; 人生格言#xff1a; 人生… 简介 CSDN博客专家专注Android/Linux系统分享多mic语音方案、音视频、编解码等技术与大家一起成长 优质专栏Audio工程师进阶系列【原创干货持续更新中……】 人生格言 人生从来没有捷径只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注Android系统攻城狮 1.前言 本篇目的理解C之std::atomic原子操作解决多线程竟态问题用法。 2.std::atomic可以解决的C多线程问题
在C中std::atomic提供了一种线程安全的访问原子类型的机制可以解决以下七个多线程之间的问题
竞态条件Race Condition多个线程同时访问和修改同一个变量时可能导致数据错误。内存可见性Memory Visibility不同线程对共享变量的修改可能不可见导致读取到过期的值。乱序执行Out-of-Order Execution处理器可能以不同的顺序执行指令导致结果的不确定性。死锁Deadlock多个线程相互等待对方释放资源导致程序无法继续执行。活锁Live Lock多个线程相互响应对方的动作而无法继续向前推进。数据竞争Data Race多个线程同时访问和修改共享数据没有同步机制可能导致不确定的行为。优先级反转Priority Inversion高优先级任务被低优先级任务持续占用共享资源导致高优先级任务无法及时执行。
3.应用实例
竞态条件Race Condition
v1.0 未使用atomic原子操作
#include atomic
#include thread
#include cstdio//std::atomicint counter(0); // 原子变量
int counter 0; // 普通变量void increment() {for (int i 0; i 1000; i) {counter; // 原子操作递增printf(counter %d\n,counter);//打印出来的数据是乱序的}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();return 0;
}v2.0 使用atomic原子操作
#include atomic
#include threadstd::atomicint counter(0); // 原子变量void increment() {for (int i 0; i 1000; i) {counter; // 原子操作递增printf(counter %d\n,counter.load());//按顺序打印0 - 2000. }
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();return 0;
}多个线程同时对counter进行递增操作使用std::atomic可以避免竞态条件保证递增操作的原子性。
内存可见性Memory Visibility
#include atomic
#include thread
#include iostreamstd::atomicbool flag(false); // 原子标志void run() {while (!flag.load()) {// do something}printf(flag %d\n,flag.load());
}int main() {std::thread t(run);// 假设这里执行一些耗时的计算std::this_thread::sleep_for(std::chrono::seconds(1));flag.store(true); // 原子操作标志位置为truet.join();return 0;
}
flag作为一个标志位在一个线程中修改为true其他线程可以通过读取flag的原子操作来感知到修改保证内存的可见性。
乱序执行Out-of-Order Execution
#include atomic
#include thread
#include iostreamstd::atomicint value(0); // 原子变量void write() {value.store(42, std::memory_order_relaxed); // 原子操作无序存储
}void read() {while (value.load(std::memory_order_relaxed) 0) {// do something}std::cout Value: value.load(std::memory_order_relaxed) std::endl;
}int main() {std::thread t1(write);std::thread t2(read);t1.join();t2.join();return 0;
}通过使用适当的内存顺序(memory_order)来进行原子操作可以避免乱序执行带来的问题例如使用std::memory_order_relaxed来指定无序存储。
死锁Deadlock
#include atomic
#include mutex
#include threadstd::atomicbool flag1(false);
std::atomicbool flag2(false);std::mutex mutex1;
std::mutex mutex2;void process1() {mutex1.lock(); // 获取锁1// 假设这里执行一些操作flag1.store(true); // 标记为已处理mutex2.lock(); // 获取锁2// 执行需要锁2的操作mutex2.unlock();mutex1.unlock();
}void process2() {mutex2.lock(); // 获取锁2// 假设这里执行一些操作flag2.store(true); // 标记为已处理mutex1.lock(); // 获取锁1// 执行需要锁1的操作mutex1.unlock();mutex2.unlock();
}int main() {std::thread t1(process1);std::thread t2(process2);t1.join();t2.join();return 0;
}多个线程对两个互斥量(mutex)进行获取操作可能导致死锁std::atomic不能直接解决死锁问题但可以用来作为线程间的通信机制。
活锁Live Lock
#include atomic
#include thread
#include iostreamstd::atomicbool flag1(false);
std::atomicbool flag2(false);void process1() {while (!flag2) {// 假设这里执行一些操作// 暂停一段时间避免忙等待std::this_thread::sleep_for(std::chrono::milliseconds(100));flag1.store(true);// 假设这里还有其他判断逻辑}
}void process2() {while (!flag1.load()) {// 假设这里执行一些操作// 暂停一段时间避免忙等待std::this_thread::sleep_for(std::chrono::milliseconds(100));flag2.store(true);// 假设这里还有其他判断逻辑}
}int main() {std::thread t1(process1);std::thread t2(process2);t1.join();t2.join();std::cout Live lock detected! std::endl;return 0;
}两个线程互相等待对方设置标志位但由于不断地执行操作和忙等待两个线程无法继续前进造成活锁。
数据竞争Data Race
#include atomic
#include thread
#include iostreamstd::atomicint counter(0); // 原子计数器void increment() {for (int i 0; i 1000; i) {int temp counter.load(); // 读取计数器的当前值counter.store(temp 1); // 原子操作递增}
}int main() {std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout Counter: counter.load() std::endl;return 0;
}两个线程同时读取和修改计数器的值使用std::atomic可以避免数据竞争保证计数器的正确递增。
优先级反转Priority Inversion
#include atomic
#include thread
#include iostreamstd::atomicint sharedResource(0); // 共享资源void lowPriorityThread() {while (true) {// 低优先级任务需要访问共享资源while (sharedResource.load() 0) {// do something}std::cout Low priority thread accessing shared resource. std::endl;// 假设这里执行一些低优先级任务的操作// 完成低优先级任务后释放共享资源sharedResource.store(0);}
}void highPriorityThread() {// 高优先级任务需要持有共享资源sharedResource.store(1);std::cout High priority thread acquired shared resource. std::endl;// 假设这里执行一些高优先级任务的操作// 完成高优先级任务后释放共享资源sharedResource.store(0);
}int main() {std::thread t1(lowPriorityThread);std::thread t2(highPriorityThread);t1.join();t2.join();return 0;
}