当前位置: 首页 > news >正文

C++面试4-线程同步

分类名称C++标准Windows APIPOSIX/Linux功能描述
互斥锁std::mutexCRITICAL_SECTION / CreateMutexpthread_mutex_t保证同一时刻仅一个线程访问共享资源
自旋锁std::atomic_flag-pthread_spinlock_t忙等方式锁,适合短时间加锁
读写锁std::shared_mutex (C++17)SRWLockpthread_rwlock_t多读单写并行
条件变量std::condition_variableConditionVariablepthread_cond_t等待条件满足再继续执行
信号量std::counting_semaphore (C++20)CreateSemaphoresem_t控制同时访问共享资源的线程数
原子操作std::atomic<T>Interlocked* 系列__sync_fetch_and_add无锁同步,轻量高效
事件-CreateEventpthread_cond_signal 模拟用于线程间通知或唤醒
屏障std::barrier (C++20)-pthread_barrier_t等所有线程到达同一点后一起继续

二、各类同步机制示例

1️⃣ 互斥锁(mutex)

✅ C++ 标准版

#include <iostream>
#include <thread>
#include <mutex>

int counter = 0;
std::mutex mtx;

void add() {
for (int i = 0; i < 100000; ++i) {
std::lock_guard<std::mutex> lock(mtx); // 自动加解锁
++counter;
}
}

int main() {
std::thread t1(add), t2(add);
t1.join(); t2.join();
std::cout << "counter = " << counter << std::endl;
}
counter = 200000

#include <windows.h>
#include <iostream>

Window 版本:

CRITICAL_SECTION cs;
int counter = 0;

DWORD WINAPI add(LPVOID) {
for (int i = 0; i < 100000; ++i) {
EnterCriticalSection(&cs);
++counter;
LeaveCriticalSection(&cs);
}
return 0;
}

int main() {
InitializeCriticalSection(&cs);
HANDLE t1 = CreateThread(nullptr, 0, add, nullptr, 0, nullptr);
HANDLE t2 = CreateThread(nullptr, 0, add, nullptr, 0, nullptr);
WaitForMultipleObjects(2, new HANDLE[2]{t1, t2}, TRUE, INFINITE);
std::cout << "counter = " << counter << std::endl;
DeleteCriticalSection(&cs);
}


2 条件变量(condition_variable)

#include <condition_variable>
#include <mutex>
#include <thread>
#include <queue>
#include <iostream>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> q;
bool done = false;

void producer() {
for (int i = 0; i < 5; ++i) {
{
std::lock_guard<std::mutex> lock(mtx);
q.push(i);
}
cv.notify_one();
}
done = true;
cv.notify_all();
}

void consumer() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [] { return !q.empty() || done; });
if (!q.empty()) {
std::cout << "Consume: " << q.front() << "\n";
q.pop();
} else if (done) break;
}
}

int main() {
std::thread t1(producer), t2(consumer);
t1.join(); t2.join();
}


打印:

Consume: 0
Consume: 1
Consume: 2
Consume: 3
Consume: 4

3  信号量(semaphore)

#include <iostream>
#include <thread>
#include <semaphore>

std::counting_semaphore<2> sem(2); // 最多允许2线程同时访问

void worker(int id) {
sem.acquire();
std::cout << "Thread " << id << " working\n";
std::this_thread::sleep_for(std::chrono::milliseconds(500));
sem.release();
}

int main() {
std::thread t1(worker, 1), t2(worker, 2), t3(worker, 3);
t1.join(); t2.join(); t3.join();
}
4️⃣ 原子变量(atomic)

#include <atomic>
#include <thread>
#include <iostream>

std::atomic<int> counter = 0;

void add() {
for (int i = 0; i < 100000; ++i)
counter.fetch_add(1);
}

int main() {
std::thread t1(add), t2(add);
t1.join(); t2.join();
std::cout << "counter = " << counter << std::endl;
}

5️⃣ 读写锁(shared_mutex)

#include <shared_mutex>
#include <thread>
#include <iostream>

std::shared_mutex rwlock;
int data = 0;

void reader(int id) {
std::shared_lock<std::shared_mutex> lock(rwlock);
std::cout << "Reader " << id << " reads " << data << "\n";
}

void writer(int id) {
std::unique_lock<std::shared_mutex> lock(rwlock);
++data;
std::cout << "Writer " << id << " updates to " << data << "\n";
}

int main() {
std::thread t1(writer, 1);
std::thread t2(reader, 2);
std::thread t3(reader, 3);
t1.join(); t2.join(); t3.join();
}

三、选择建议总结

场景推荐同步方式原因
数据访问互斥std::mutex / pthread_mutex_t经典安全
短时间锁竞争自旋锁 / 原子操作避免上下文切换
生产者-消费者条件变量 + 队列高效等待唤醒
多读少写数据读写锁读多线程并行
控制资源数量信号量可同时运行 N 个线程
多线程阶段同步屏障 std::barrier阶段性同步
事件触发/通知条件变量 / Windows Event明确触发唤醒机制

Writer 1 updates to 1
Reader 2 reads 1
Reader 3 reads 1

这是理解多线程同步机制的重要一环。我们来一步步详细拆解:

一、首先复习一下:锁的目的

多线程编程中,多个线程同时访问共享资源(变量、文件、内存等)时,会产生数据竞争(Data Race)不一致性(Inconsistency)

为防止这种情况,我们用各种同步原语(Synchronization Primitives)控制访问顺序

  • std::mutex:互斥锁

  • std::recursive_mutex:可重入互斥锁

  • std::timed_mutex:带超时的互斥锁

  • std::shared_mutex(C++17):读写锁(shared-exclusive lock)

  • 二、读写锁(shared_mutex)是什么?

    读写锁是一种特殊的互斥机制,它区分了两种访问:

类型权限是否互斥适用场景
读锁(shared lock)只读访问多个线程可以同时加读锁多线程“读多写少”
写锁(unique lock)修改访问只能有一个线程加写锁,且此时不能有任何读锁修改共享数据时

🧩 三、为什么要用读写锁,而不是普通互斥锁?

✅ 1. 提升并发性能

普通的 mutex完全互斥的:

  • 线程 A 正在读取数据;

  • 线程 B 想读,也得等;

  • 明明两个线程都只读,没有写操作,其实不会互相影响,但 mutex 仍强制串行化。

这会大大降低性能。

读写锁 允许:

多个线程同时读取,只在写入时互斥。

这对“读多写少”的场景(例如缓存查询、配置读取)性能提升明显。

✅ 2. 避免不必要的等待

std::shared_mutex rwLock;
int value = 0;

void reader(int id) {
std::shared_lock lock(rwLock); // 读锁
std::cout << "Reader " << id << " sees value = " << value << "\n";
}

void writer(int id) {
std::unique_lock lock(rwLock); // 写锁
++value;
std::cout << "Writer " << id << " modifies value = " << value << "\n";
}

如果我们用普通 std::mutex

  • 即使 10 个线程都只是读取 value,也得一个个排队;

  • shared_mutex,这 10 个线程可以同时读。

✅ 3. 资源访问模式不同

互斥锁(mutex)保护的是「谁都不能同时访问」;
读写锁(rwlock)保护的是「谁不能同时写」。

场景用互斥锁用读写锁
只有一个房门,所有人都排队进✅ 合理但慢⚠️ 太保守
图书馆:很多人能同时看书,只有管理员能改书❌ 阻塞所有人✅ 高效

#include <iostream>
#include <thread>
#include <shared_mutex>
#include <vector>
#include <chrono>

std::shared_mutex rwLock;
int data = 0;

void reader(int id) {
for (int i = 0; i < 3; ++i) {
std::shared_lock<std::shared_mutex> lock(rwLock); // 读锁
std::cout << "Reader " << id << " reads data = " << data << "\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}

void writer(int id) {
for (int i = 0; i < 3; ++i) {
std::unique_lock<std::shared_mutex> lock(rwLock); // 写锁
++data;
std::cout << "Writer " << id << " writes data = " << data << "\n";
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}

int main() {
std::vector<std::thread> threads;
// 1个写者,3个读者
threads.emplace_back(writer, 1);
for (int i = 0; i < 3; ++i)
threads.emplace_back(reader, i+1);

    for (auto &t : threads)
t.join();
}

http://www.dtcms.com/a/577684.html

相关文章:

  • 【LeetCode热题100(62/100)】搜索二维矩阵
  • 并发编程、锁、线程池知识整理<1>
  • 11种方法解决iPhone上共享相册不显示的问题[2025]
  • php网站制作教程美食网站开发的技术简介
  • Spring整合单元测试
  • 深入浅出理解克尔效应(Kerr Effect)及 MATLAB 仿真实现
  • 【区块链】二、案例1:汽车供应链区块链
  • 影刀RPA一键批量上传商品视频!AI智能处理,效率提升2000%[特殊字符]
  • 安卓/IOS工具开发基础教程:按键精灵一个简单的文字识别游戏验证
  • Python爬虫实战:澳元-人民币汇率历史数据获取与趋势分析
  • 网站开发属于大学那个专业网页设计题材
  • 图书馆网站建设的项目报告网站svg使用
  • 基于大数据的短视频流量数据分析与可视化
  • OT83211_VC1:4通道 ASRC OTG(44.1kHz~192kHz)音频采样率转换器产品介绍
  • 性能测试需求分析详解
  • Redis-面试问题
  • 小型网站开发用什么语言大型h5手游平台
  • 徐州网站建设工作室中国建筑官网首页
  • MyBatis注解的运用于条件搜索实践
  • 搭建网站 软件下载吴忠市建设局官方网站
  • 工厂方法模式:从理论到实战指南
  • 微信小程序 点击地图后弹出一个模态框
  • 3.6.6【2021统考真题】
  • 《道德经》第五十章
  • 分类问题的基石:逻辑回归(Logistic Regression)
  • 机器学习实践项目(二)- 房价预测增强篇 - 特征工程二
  • Jenkins自动部署CI/CD
  • 【unity】PowerVR GE8320系列GPU渲染问题分析
  • 做网站设计需要哪些知识网页游戏排行榜回合制
  • 从理论到实践:深度解析昇腾CANN训练营中的Ascend C编程模型