创建一个C++线程需要传入几个参数?
如何理解和使用C++线程循环
C++ 类 函数 变量 进程 线程
C++关于锁和互斥量你真的理解了吗
C++ 代码中如何使用互斥锁std::mutex和独占锁std::unique_lock
在 C++ 中,互斥量(Mutex,即 Mutual Exclusion)是并发编程中的一种基本工具,用于控制多个线程对共享资源的访问,以防止数据竞争和相关的未定义行为。互斥量提供了一种机制,允许一个线程一次只锁定一次资源,确保在该线程释放互斥量之前,其他线程不能访问被保护的资源。
互斥量可以被视为一种锁,用来保护共享数据,确保在任何时候只有一个线程可以访问这些数据。当一个线程需要访问被互斥量保护的资源时,它必须先锁定(acquire)这个互斥量。如果互斥量已被另一个线程锁定,该线程将被阻塞,直到互斥量被释放(unlock)。这防止了多个线程同时读写同一数据,从而防止了数据损坏和不一致性。
C++ 标准库提供了 <mutex>
头文件,其中包含用于管理互斥量的类。最常用的类是 std::mutex
。以下是 std::mutex
的基本用法:
#include <iostream>
#include <mutex>
std::mutex mtx; // 定义一个互斥量
void function() {
mtx.lock(); // 锁定互斥量
// ... 执行需要互斥的操作 ...
mtx.unlock(); // 解锁互斥量
}
#include <iostream>
#include <mutex>
std::mutex mtx; // 全局互斥锁
void print_function(const std::string& message) {
mtx.lock(); // 手动锁定
std::cout << message << std::endl;
mtx.unlock(); // 手动解锁
}
int main() {
print_function("Hello from main function");
return 0;
}
main
函数直接调用 print_function
,而不是创建新线程来调用它。print_function
依然使用 mtx.lock()
和 mtx.unlock()
来手动管理互斥锁,尽管在单线程环境中这实际上是不必要的。请注意,在单线程程序中使用互斥锁通常是没有必要的,因为没有并发访问共享资源的风险。此示例仅用于说明如何单独使用 std::mutex
。在实际应用中,您应该根据程序的并发需求来决定是否使用互斥锁。
std::lock_guard
自动管理锁为了避免忘记解锁或在异常发生时遗漏解锁,可以使用 std::lock_guard
,它提供了一种自动管理锁的方法(RAII,资源获取即初始化)。
void safe_function() {
std::lock_guard<std::mutex> lock(mtx);
// ... 执行需要互斥的操作 ...
} // `lock_guard` 在作用域结束时自动释放互斥量
std::unique_lock
获得更多控制std::unique_lock<std::mutex>
提供了比 std::lock_guard
更多的灵活性,允许你延迟锁定,重复锁定和解锁,以及移动锁。
void flexible_function() {
std::unique_lock<std::mutex> lock(mtx, std::defer_lock);
// ... 这里互斥量还未锁定 ...
lock.lock(); // 手动锁定
// ... 执行需要互斥的操作 ...
lock.unlock(); // 可以手动解锁
// ... 可以在不同的时间点再次锁定 ...
}
std::lock_guard
和 std::unique_lock
在这方面非常有用。正确地使用互斥量可以确保多线程程序的正确性和稳定性,但需要谨慎使用以避免常见的陷阱,如死锁和性能瓶颈。
在 C++ 中,除了 std::mutex
,标准库提供了几种不同类型的锁,以适应不同的并发和同步需求。下面是一些常见的锁类型及其简要说明:
std::mutex:
std::mutex
提供了基本的锁定和解锁功能,但没有递归锁定的能力。std::recursive_mutex:
std::timed_mutex:
std::recursive_timed_mutex:
std::recursive_mutex
和 std::timed_mutex
的特性。它是一个可以由同一线程多次锁定的互斥锁,同时提供了带超时的锁定尝试。std::shared_mutex (C++17):
std::shared_timed_mutex (C++14):
std::shared_mutex
的一个变体,提供了超时功能。它允许多个线程同时进行读取操作,但写入操作将独占锁定。std::lock_guard:
std::unique_lock:
std::lock_guard
更灵活的作用域锁。它不仅允许在构造时延迟锁定,还可以在生命周期内多次锁定和解锁互斥锁。这些锁的选择和使用取决于特定的应用场景和性能要求。例如,对于简单的互斥需求,std::mutex
和 std::lock_guard
通常就足够了。而对于需要更精细控制的场景,如需要超时或递归锁定功能,你可能需要选择 std::timed_mutex
或 std::recursive_mutex
等更高级的锁类型。