聊一下 c++ 的std::mutex

std::mutex 是 C++11 引入的一个工具,用来管多线程抢资源的问题,简单又实用。

啥是 std::mutex?

想象你在家吃饭,桌上只有一碗饭,但有俩人(线程)同时伸手抢。没规矩就乱了,可能饭洒了还吃不上。std::mutex 就像个“饭碗锁”,谁拿了锁谁吃饭,别人得等着,吃了放回去再给下一个人。

简单说:std::mutex 是一个互斥锁(Mutex),用来保护共享资源,让多线程安全访问。

为啥用它? 防抢:多线程同时改同一块数据会乱,锁住就安全。 简单:比手动协调线程省事。 标准:C++ 自带,哪儿都能用。

怎么用? 得先包含头文件 ,然后就能玩了。

  1. 基本用法
#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx; // 定义一个锁
int count = 0;  // 共享资源

void increment() {
    mtx.lock();         // 上锁
    count++;            // 改共享数据
    std::cout << "Count: " << count << "\n";
    mtx.unlock();       // 解锁
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    return 0;
}

输出(顺序可能变):

Count: 1
Count: 2

std::mutex mtx:创建锁。

lock():上锁,没锁住就等着。

unlock():解锁,放手让别人用。

俩线程抢着加 count,锁保证一次只能一个干。

2. 用 RAII(推荐)

手动 lock/unlock 容易忘解锁,C++ 提供了 std::lock_guard,死了自动解:

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

std::mutex mtx;
int count = 0;

void increment() {
    std::lock_guard<std::mutex> guard(mtx); // 上锁
    count++;                                // 安全操作
    std::cout << "Count: " << count << "\n";
} // guard 死了,自动解锁

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    return 0;
}

std::lock_guard:构造时锁上,析构时解开,省心。 输出同上,但更安全。

3. 带条件的锁

如果不想一直等着,可以用 try_lock:

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

std::mutex mtx;
int count = 0;

void increment(int id) {
    if (mtx.try_lock()) { // 尝试上锁
        count++;
        std::cout << "线程 " << id << " 成功加: " << count << "\n";
        mtx.unlock();
    } else {
        std::cout << "线程 " << id << " 没抢到锁\n";
    }
}

int main() {
    std::thread t1(increment, 1);
    std::thread t2(increment, 2);
    t1.join();
    t2.join();
    return 0;
}

输出(可能):

线程 1 成功加: 1
线程 2 没抢到锁

try_lock():试着锁,成功返回 true,失败返回 false,不阻塞。

4. 更高级:unique_lock

std::uniquelock 比 lockguard 灵活,能手动解锁:

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

std::mutex mtx;
int count = 0;

void increment() {
    std::unique_lock<std::mutex> lock(mtx); // 上锁
    count++;
    lock.unlock(); // 手动解锁
    std::cout << "Count: " << count << "\n"; // 解锁后再干别的
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    t1.join();
    t2.join();
    return 0;
}

std::uniquelock:可以中途解锁,或者延迟锁(deferlock),更自由。

5. 多个锁:防死锁

如果有俩锁,防止线程互相卡死:

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

std::mutex mtx1, mtx2;

void task1() {
    std::lock(mtx1, mtx2); // 一次锁住俩
    std::lock_guard<std::mutex> l1(mtx1, std::adopt_lock);
    std::lock_guard<std::mutex> l2(mtx2, std::adopt_lock);
    std::cout << "任务1 拿到了俩锁\n";
}

void task2() {
    std::lock(mtx2, mtx1); // 顺序反着也行
    std::lock_guard<std::mutex> l2(mtx2, std::adopt_lock);
    std::lock_guard<std::mutex> l1(mtx1, std::adopt_lock);
    std::cout << "任务2 拿到了俩锁\n";
}

int main() {
    std::thread t1(task1);
    std::thread t2(task2);
    t1.join();
    t2.join();
    return 0;
}

注意点

  • 别忘解锁: 手动 lock() 一定要配 unlock(),不然卡死。

用 lockguard 或 uniquelock 就不用操心。

  • 性能:

锁多了线程会排队,太频繁影响效率。

  • 死锁:

俩线程互相等锁会卡死,用 std::lock 或小心顺序。

需要掌握啥?

基本锁:lock() 和 unlock()。

RAII:std::lock_guard 简单安全。

灵活锁:std::unique_lock 手动控制。

试锁:try_lock() 不想等时用。

多锁:std::lock() 防死锁。

场景:保护共享数据,比如计数器、文件。

总结

std::mutex 是 C++ 的锁,管住多线程抢资源。

用法:手动 lock/unlock,或用 lockguard/uniquelock 自动管理。

核心是安全访问共享数据,现代多线程必备。

文档信息

版权声明:可自由转载(请注明转载出处)-非商用-非衍生

发表时间:2025年7月1日 12:16