C++中的锁机制

举报
无敌清风蓝 发表于 2023/06/13 13:49:03 2023/06/13
【摘要】 C++中的锁机制

1.介绍

加锁是一种用于保护临界区的方法。它的基本思想是使用一个锁来控制对临界区的访问。当一个线程需要进入临界区时,它必须先获得锁;当它离开临界区时,它必须释放锁。如果锁已经被其他线程占用,那么当前线程将被阻塞,直到锁被释放。

C++11 引入了多线程支持,包括对锁的支持。C++11 中提供了多种类型的锁,包括 `std::mutex`、`std::recursive_mutex`、`std::timed_mutex` 和 `std::recursive_timed_mutex`。

`std::mutex` 是最基本的一种锁,它提供了两个方法:`lock()` 和 `unlock()`。当一个线程需要进入临界区时,它可以调用 `lock()` 方法来获得锁;当它离开临界区时,它必须调用 `unlock()` 方法来释放锁。

2.例子

下面是一个简单的示例:

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

std::mutex mtx;

void print() {
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << "Hello from thread " << std::this_thread::get_id() << std::endl;
}

int main() {
    std::thread t1(print);
    std::thread t2(print);

    t1.join();
    t2.join();

    return 0;
}

在这个示例中,我们定义了一个全局的 `std::mutex` 对象 `mtx` 来保护对 `std::cout` 的访问。在 `print()` 函数中,我们使用了 `std::lock_guard` 来自动管理锁的生命周期。当 `std::lock_guard` 对象创建时,它会自动调用 `mtx.lock()` 来获得锁;当它销毁时,它会自动调用 `mtx.unlock()` 来释放锁。

这样,当两个线程同时调用 `print()` 函数时,只有一个线程能够获得锁并进入临界区,另一个线程将被阻塞。这样就避免了数据竞争和不一致的结果。

`t1.join()` 和 `t2.join()` 这两行代码分别用于等待线程 `t1` 和 `t2` 结束。`join()` 方法会阻塞当前线程,直到被调用的线程结束。

在上面的示例中,`main()` 函数中创建了两个线程 `t1` 和 `t2`,它们都执行 `print()` 函数。当 `main()` 函数执行到 `t1.join()` 时,它会阻塞并等待线程 `t1` 结束。当线程 `t1` 结束后,`main()` 函数继续执行,并调用 `t2.join()` 来等待线程 `t2` 结束。当线程 `t2` 结束后,`main()` 函数继续执行,并最终退出。

使用 `join()` 方法可以确保在线程结束之前不会退出程序。如果不调用 `join()` 方法,那么主线程可能会在其他线程结束之前退出,导致未定义的行为

这段代码创建了两个线程 `t1` 和 `t2`,它们都执行 `print()` 函数。由于我们使用了锁来保护对 `std::cout` 的访问,所以两个线程的输出不会交叉。因此,这段代码的一个可能的输出结果是:

Hello from thread 1
Hello from thread 2

或者:

Hello from thread 2
Hello from thread 1

具体的输出顺序取决于线程的调度顺序,这是不确定的。

`std::thread t1(print);` 和 `std::thread t2(print);` 这两行代码分别创建了两个线程 `t1` 和 `t2`。它们都执行 `print()` 函数,但是它们是两个独立的线程,它们之间没有直接的关系。除了执行相同的函数之外,它们没有其他区别。

如果不加锁,那么两个线程可能会同时访问 `std::cout`,导致输出结果交叉。例如,一个可能的输出结果是:

HeHlleollo  ffrroomom  tthhrreeaadad  11
Hello from thread 2

由于线程的调度顺序是不确定的,所以输出结果也是不确定的。在实际应用中,不加锁可能会导致数据竞争和不一致的结果,因此应该避免这种情况。

“HeHlleollo ffrroomom tthhrreeaadad 11” 是一个可能的输出结果,用来说明当两个线程同时访问 `std::cout` 时可能会发生什么。

在这个例子中,两个线程同时执行 `print()` 函数,它们都试图向 `std::cout` 输出字符串 “Hello from thread X”(其中 X 是线程的 ID)。由于没有加锁来保护对 `std::cout` 的访问,所以两个线程的输出可能会交叉。

例如,线程 1 可能输出了 “H”,然后线程 2 输出了 “H”,然后线程 1 输出了 “e”,然后线程 2 输出了 “e”,以此类推。最终的结果就是 “HeHlleollo ffrroomom tthhrreeaadad 11”。

需要注意的是,这只是一个可能的输出结果。实际的输出结果取决于线程的调度顺序和操作系统的实现细节,它是不确定的。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。