当前位置: 首页
编程语言
Linux下C++如何处理多线程同步

Linux下C++如何处理多线程同步

热心网友 时间:2026-05-04
转载

Linux下C++多线程同步:从互斥锁到屏障的实战指南

在Linux平台上用C++搞多线程开发,线程同步是个绕不开的核心议题。处理不好,数据竞争、死锁这些“坑”随时可能出现。那么,有哪些趁手的同步工具可供选择呢?它们的典型用法又是怎样的?

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

Linux下C++如何处理多线程同步

下面,我们就来梳理几种C++标准库中常用的线程同步机制,并配上直观的代码示例。

1. 互斥锁(Mutex)

这大概是大家最熟悉的同步原语了。它的职责非常明确:保护共享资源,确保同一时刻只有一个线程能访问它,相当于给临界区上了一把独占的锁。

#include 
#include 
#include 

std::mutex mtx; // 定义一个互斥锁

void print_block(int n, char c) {
    mtx.lock(); // 加锁
    for (int i = 0; i < n; ++i) {
        std::cout << c;
    }
    std::cout << '\n';
    mtx.unlock(); // 解锁
}

int main() {
    std::thread th1(print_block, 50, '*');
    std::thread th2(print_block, 50, '$');
    th1.join();
    th2.join();
    return 0;
}

看这段代码,两个线程都想往控制台打印字符。如果没有互斥锁,输出可能会混杂在一起。而mtx.lock()mtx.unlock()这对操作,就保证了每个线程的打印区块是完整的。

2. 递归互斥锁(Recursive Mutex)

普通互斥锁有个限制:同一个线程不能重复上锁,否则会立刻导致死锁。但有些场景下,我们可能需要函数递归调用,或者一个公共函数本身就需要加锁。这时候,递归互斥锁就派上用场了。

#include 
#include 
#include 

std::recursive_mutex mtx; // 定义一个递归互斥锁

void print_block(int n, char c) {
    mtx.lock(); // 加锁
    if (n > 0) {
        std::cout << c;
        mtx.lock(); // 再次加锁
        print_block(n - 1, c);
        mtx.unlock(); // 解锁
    }
    std::cout << '\n';
    mtx.unlock(); // 解锁
}

int main() {
    std::thread th1(print_block, 50, '*');
    std::thread th2(print_block, 50, '$');
    th1.join();
    th2.join();
    return 0;
}

注意看,在递归函数print_block内部,同一个线程对mtx执行了多次lock()。如果换成普通的std::mutex,程序就会卡住。而std::recursive_mutex允许这种行为,只要确保加锁和解锁的次数匹配即可。

3. 条件变量(Condition Variable)

互斥锁解决了互斥访问的问题,但线程间有时需要“等待某个条件成立”。比如,一个线程要等队列非空才能取数据,另一个线程放入数据后需要通知它。这就是条件变量的典型应用场景。

#include 
#include 
#include 
#include 

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void print_id(int id) {
    std::unique_lock lck(mtx);
    cv.wait(lck, []{return ready;}); // 等待条件变量
    std::cout << "Thread " << id << '\n';
}

void go() {
    std::lock_guard lck(mtx);
    ready = true;
    cv.notify_all(); // 通知所有等待的线程
}

int main() {
    std::thread threads[10];
    for (int i = 0; i < 10; ++i) {
        threads[i] = std::thread(print_id, i);
    }
    std::this_thread::sleep_for(std::chrono::seconds(1)); // 等待一段时间
    go(); // 通知线程开始执行
    for (auto& th : threads) {
        th.join();
    }
    return 0;
}

这个例子展示了经典的“等待-通知”模式。10个线程启动后都在条件变量cv上等待,直到主线程调用go()ready置为true并发出notify_all()信号,所有等待的线程才继续执行。cv.wait()的第二个参数是一个谓词(lambda表达式),它避免了虚假唤醒,是更健壮的写法。

4. 读写锁(Reader-Writer Lock)

对于“读多写少”的共享数据,使用互斥锁会限制并发性能,因为读操作之间本可以不互斥。读写锁(C++17起为std::shared_mutex)应运而生,它允许多个读线程同时持有锁,但写线程独占锁。

#include 
#include 
#include 

std::shared_mutex rw_mtx; // 定义一个读写锁
int shared_data = 0;

void read_data() {
    std::shared_lock lck(rw_mtx); // 读锁
    std::cout << "Read data: " << shared_data << '\n';
}

void write_data(int value) {
    std::unique_lock lck(rw_mtx); // 写锁
    shared_data = value;
    std::cout << "Write data: " << shared_data << '\n';
}

int main() {
    std::thread readers[5];
    std::thread writer(write_data, 42);
    for (auto& th : readers) {
        th = std::thread(read_data);
    }
    for (auto& th : readers) {
        th.join();
    }
    writer.join();
    return 0;
}

使用时要注意区分:读操作使用std::shared_lock,写操作使用std::unique_lock。这样,多个read_data线程可以并发执行,而write_data线程执行时,所有读写线程都必须等待。

5. 屏障(Barrier)

最后来看看屏障。它的概念很简单:设置一个同步点,要求指定数量的线程都到达这个点后,大家才能一起继续往下执行。这在分阶段并行计算的场景中非常有用。

#include 
#include 
#include 
#include 

std::barrier sync_point(3); // 定义一个屏障,等待3个线程

void do_work(int id) {
    std::cout << "Thread " << id << " is working\n";
    sync_point.arrive_and_wait(); // 等待其他线程
    std::cout << "Thread " << id << " has passed the barrier\n";
}

int main() {
    std::vector threads;
    for (int i = 0; i < 3; ++i) {
        threads.emplace_back(do_work, i);
    }
    for (auto& th : threads) {
        th.join();
    }
    return 0;
}

代码中,屏障sync_point被设置为需要等待3个线程。每个线程完成自己的“工作”阶段后,调用arrive_and_wait(),直到另外两个线程也到达此处,三个线程才会同时继续执行“通过屏障后”的代码。

以上就是C++中几种主流的线程同步机制。简单总结一下:互斥锁是基础,递归互斥锁解决特定嵌套问题,条件变量用于线程间协作,读写锁优化读多写少场景,屏障则用于阶段性的线程汇合。在实际开发中,根据具体的需求场景选择合适的同步工具,是构建健壮、高效多线程程序的关键一步。

来源:https://www.yisu.com/ask/42460512.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
Linux下C++如何处理多线程同步

Linux下C++如何处理多线程同步

Linux下C++多线程同步:从互斥锁到屏障的实战指南 在Linux平台上用C++搞多线程开发,线程同步是个绕不开的核心议题。处理不好,数据竞争、死锁这些“坑”随时可能出现。那么,有哪些趁手的同步工具可供选择呢?它们的典型用法又是怎样的? 下面,我们就来梳理几种C++标准库中常用的线程同步机制,并配

时间:2026-05-04 22:48
C++在Linux上如何进行文件操作

C++在Linux上如何进行文件操作

在Linux上使用C++进行文件操作 说到在Linux环境下用C++处理文件,这个标准库头文件绝对是你的首选工具箱。它封装了一套直观的输入输出流接口,让文件读写变得像控制台输入输出一样顺手。下面,咱们就通过几个典型的场景,来看看它的基本用法。 1 打开文件 操作文件的第一步,自然是打开它。这里用s

时间:2026-05-04 22:48
Linux C++如何提高代码执行效率

Linux C++如何提高代码执行效率

在Linux环境下提升C++代码执行效率:一份实战指南 在Linux平台上用C++开发高性能应用,效率是绕不开的核心议题。代码反赌不快,往往直接决定了系统的吞吐能力和响应速度。那么,如何才能让C++程序在Linux环境下“火力全开”呢?这需要我们从算法选择、代码编写、编译器调优,一直到系统资源管理,

时间:2026-05-04 22:47
C++ Linux系统中怎样调试程序

C++ Linux系统中怎样调试程序

在Linux系统中,有多种方法可以用来调试C++程序 对于在Linux环境下进行C++开发的工程师来说,调试是绕不开的一环。面对复杂的逻辑或隐秘的Bug,手头没有几件趁手的工具可不行。好在Linux生态提供了丰富且强大的调试选项,从经典的命令行工具到现代的集成环境,再到专门的内存和性能分析器,足以应

时间:2026-05-04 22:47
Debian系统下Go语言打包有哪些注意事项

Debian系统下Go语言打包有哪些注意事项

在Debian系统下使用Go语言进行打包时,需要注意以下几个方面 将Go应用打包部署到Debian系统,看似是常规操作,但其中有不少细节值得推敲。处理得当,部署过程行云流水;忽略某些环节,则可能遇到意想不到的麻烦。下面就来梳理一下整个流程中的关键点。 1 环境准备 万事开头难,打好基础是关键。 安

时间:2026-05-04 22:47
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜
热门教程
更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程