C++中的锁机制

简介: 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”。

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

相关文章
|
2月前
|
缓存 算法 程序员
C++STL底层原理:探秘标准模板库的内部机制
🌟蒋星熠Jaxonic带你深入STL底层:从容器内存管理到红黑树、哈希表,剖析迭代器、算法与分配器核心机制,揭秘C++标准库的高效设计哲学与性能优化实践。
C++STL底层原理:探秘标准模板库的内部机制
|
7月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
177 2
|
10月前
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
213 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
|
安全 C++
C++中的异常处理与错误处理机制
C++中的异常处理与错误处理机制
264 0
|
Linux API C++
c++多线程——互斥锁
c++多线程——互斥锁
|
C++
C++11 std::lock_guard 互斥锁
C++11 std::lock_guard 互斥锁
187 0
|
存储 安全 编译器
【c++】深入理解别名机制--引用
本文介绍了C++中的引用概念及其定义、特性、实用性和与指针的区别。引用是C++中的一种别名机制,通过引用可以实现类似于指针的功能,但更安全、简洁。文章详细解释了引用的定义方式、引用传参和返回值的应用场景,以及常引用的使用方法。最后,对比了引用和指针的异同,强调了引用在编程中的重要性和优势。
152 1
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化2
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
221 6
|
安全 测试技术 C++
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化1
【C++篇】从零实现 C++ Vector:深度剖析 STL 的核心机制与优化
294 7
|
Linux API C++
超级好用的C++实用库之互斥锁
超级好用的C++实用库之互斥锁
137 2