做网站 多页面网址怎么弄,广告设计与制作好找工作吗,广东中高风险地区最新名单,新郑网络推广公司“交叉打印 FooBar”是并发编程中非常经典的**同步#xff08;Synchronization#xff09;**问题。目标是让两个线程协作#xff1a;一个只负责打印 foo#xff0c;另一个只负责打印 bar#xff0c;最终输出必须是 foobarfoobar...。 在 C 中#xff0c;最常用的三种解法…“交叉打印 FooBar”是并发编程中非常经典的**同步Synchronization**问题。目标是让两个线程协作一个只负责打印foo另一个只负责打印bar最终输出必须是foobarfoobar...。在 C 中最常用的三种解法分别是互斥锁条件变量、信号量以及原子变量自旋。1. 方案一条件变量 (std::condition_variable)这是最标准、最通用的做法。通过一个布尔标志位Flag来协调两个线程。#includeiostream#includethread#includemutex#includecondition_variable#includefunctionalclassFooBar{private:intn;std::mutex mtx;std::condition_variable cv;boolfoo_donefalse;// 关键状态标志false表示该打foo了true表示该打bar了public:FooBar(intn):n(n){}voidfoo(){for(inti0;in;i){std::unique_lockstd::mutexlock(mtx);// 只要 foo_done 为 true即 bar 还没打完就等着cv.wait(lock,[this](){return!foo_done;});std::coutfoo;foo_donetrue;// 状态切换cv.notify_one();// 唤醒等待的 bar 线程}}voidbar(){for(inti0;in;i){std::unique_lockstd::mutexlock(mtx);// 只要 foo_done 为 false即 foo 还没打完就等着cv.wait(lock,[this](){returnfoo_done;});std::coutbar;foo_donefalse;// 状态切换cv.notify_one();// 唤醒等待的 foo 线程}}};2. 方案二信号量 (std::counting_semaphore - C20)信号量是处理这种“接力赛”逻辑最直观的工具。foo打印完给bar发个信号bar打印完给foo发个信号。#includesemaphoreclassFooBar{private:intn;// C20 信号量参数为 (初始计数值)std::counting_semaphore1sem_foo{1};// 初始为1foo 先跑std::counting_semaphore1sem_bar{0};// 初始为0bar 阻塞public:FooBar(intn):n(n){}voidfoo(){for(inti0;in;i){sem_foo.acquire();// 等待 foo 信号 (P操作)std::coutfoo;sem_bar.release();// 发送 bar 信号 (V操作)}}voidbar(){for(inti0;in;i){sem_bar.acquire();// 等待 bar 信号std::coutbar;sem_foo.release();// 发送 foo 信号}}};优点逻辑极其简洁不需要手动加锁和处理条件判断。3. 方案三原子变量 (std::atomic / 自旋锁)如果你追求性能且n很大、打印操作很快可以使用原子变量进行自旋。这种方式不会让线程进入内核态挂起但会消耗 CPU。#includeatomicclassFooBar{private:intn;std::atomicintflag{0};// 0打foo, 1打barpublic:FooBar(intn):n(n){}voidfoo(){for(inti0;in;i){while(flag.load(std::memory_order_acquire)!0){std::this_thread::yield();// 让出 CPU 时间片避免死等}std::coutfoo;flag.store(1,std::memory_order_release);}}voidbar(){for(inti0;in;i){while(flag.load(std::memory_order_acquire)!1){std::this_thread::yield();}std::coutbar;flag.store(0,std::memory_order_release);}}};4. 关键点深度解析为什么方案一要用unique_lock和wait如果直接用if检查标志位而不使用条件变量线程会一直占用 CPU 循环检查忙轮询。使用cv.wait会让线程进入休眠状态不消耗 CPU直到被notify唤醒。为什么方案二在旧版 C 中不常用因为在 C20 之前标准库没有内置信号量开发者必须用std::mutexstd::condition_variable自己去模拟一个信号量。内存序 (Memory Order)在方案三中我使用了memory_order_acquire/release。这不仅保证了标志位的修改可见性还防止了编译器对打印语句和标志位修改语句进行重排序确保打印动作一定在标志位切换之前完成。