You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

互斥的两个操作是否必须序列化?以C++多线程文件描述符场景为例

问题解答

是的,必须保证close(fd)和use(fd)序列化执行,同时确保is_shutdown的状态检查与这两个操作的同步——不过不一定非要用传统临界区(比如mutex),但临界区是最直观、不易出错的实现方式。

为什么当前代码会出问题

你遇到的核心问题是缺乏线程间的同步关系:

  • 虽然is_shutdown是原子变量,但默认的内存序(memory_order_seq_cst)只能保证全局操作顺序,无法确保t2的load能及时看到t1的store更新;
  • 更关键的是,close(fd)和use(fd)可能并发执行,这本身就属于对文件描述符的非法操作,即便is_shutdown检查正常,也会导致未定义行为;
  • 极端情况下,t1已经执行close(fd),但由于CPU缓存延迟,t2的is_shutdown.load()仍读到false,进而执行use(fd),触发非法访问。

可行解决方案

方案一:互斥锁实现临界区(推荐)

用互斥锁将is_shutdown的修改、close(fd)与is_shutdown的检查、use(fd)包裹成互斥的临界区,从根本上避免并发问题:

#include <iostream>
#include <atomic>
#include <mutex>

void close(int);
void use(int);
int create();

int main(){
  std::atomic<bool> is_shutdown = false;
  std::mutex mtx;
  int fd = create();
  
  std::thread t1([&](){
    std::lock_guard<std::mutex> lock(mtx);
    is_shutdown.store(true);
    close(fd);
  });
  
  std::thread t2([&]{
     std::lock_guard<std::mutex> lock(mtx);
     if(is_shutdown.load()){
         return;
     }
     use(fd);
  });
  
  t1.join();
  t2.join();
}

互斥锁的加解锁会自动建立线程间的同步:t1解锁后,t2加锁时能看到t1所有操作的最新结果,既解决了缓存一致性问题,也保证close和use不会同时执行。

方案二:原子内存序+条件变量(性能敏感场景)

如果对性能有要求,不想用互斥锁,可以通过release/acquire内存序建立同步,再配合条件变量让t1等待t2完成操作后再关闭fd:

#include <iostream>
#include <atomic>
#include <condition_variable>

void close(int);
void use(int);
int create();

int main(){
  std::atomic<bool> is_shutdown = false;
  std::atomic<bool> t2_done = false;
  std::condition_variable cv;
  std::mutex cv_mtx;
  int fd = create();
  
  std::thread t1([&](){
    is_shutdown.store(true, std::memory_order_release);
    // 等待t2完成use或提前退出
    std::unique_lock<std::mutex> lock(cv_mtx);
    cv.wait(lock, [&]{ return t2_done.load(std::memory_order_acquire); });
    close(fd);
  });
  
  std::thread t2([&]{
     if(is_shutdown.load(std::memory_order_acquire)){
         t2_done.store(true, std::memory_order_release);
         cv.notify_one();
         return;
     }
     use(fd);
     t2_done.store(true, std::memory_order_release);
     cv.notify_one();
  });
  
  t1.join();
  t2.join();
}

release/acquire内存序确保t2能及时感知is_shutdown的更新,条件变量则保证t1不会在t2使用fd的过程中关闭它。


内容的提问来源于stack exchange,提问作者xmh0511

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 00:12:07