文章我详细介绍了锁的实现,分别是C++11提供mutex,lock_guard,unique_lock,windonws提供的 mutex和Linux下提供的,方便对比使用
1.使用C++标准库提供
基本操作
创建互斥锁:std::mutex mtx;
加锁:mtx.lock();
解锁:mtx.unlock();
自动管理锁定:使用 std::lock_guard
或 std::unique_lock
进行自动加锁和解锁。
以下示例展示了如何使用 std::mutex
来保护共享资源:
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
std::mutex mtx; // 互斥锁
int counter = 0; // 共享资源
void increment_counter() {
for (int i = 0; i < 1000; ++i) {
std::lock_guard<std::mutex> lock(mtx); // 自动加锁和解锁
++counter;
// mtx.unlock() 会在 lock_guard 对象销毁时自动调用
}
}
int main() {
std::thread t1(increment_counter);
std::thread t2(increment_counter);
t1.join();
t2.join();
std::cout << "Final counter value: " << counter << std::endl;
return 0;
}
代码解释
std::mutex mtx;
:创建一个互斥锁 mtx
,用于保护共享变量 counter
。
std::lock_guard<std::mutex> lock(mtx);
:std::lock_guard
是 RAII(Resource Acquisition Is Initialization)风格的锁定工具,构造时加锁,析构时解锁,保证即使发生异常也能正确解锁。
t1.join();
和 t2.join();
:等待两个线程执行完毕。
std::unique_lock
相比 std::lock_guard
,std::unique_lock
提供了更灵活的锁管理,例如延迟加锁、显式解锁等。
代码示例
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void print_thread_id(int id) {
std::unique_lock<std::mutex> lock(mtx); // 加锁
std::cout << "Thread " << id << " is running\n";
lock.unlock(); // 手动解锁
}
int main() {
std::thread t1(print_thread_id, 1);
std::thread t2(print_thread_id, 2);
t1.join();
t2.join();
return 0;
}
代码解释
std::unique_lock<std::mutex> lock(mtx);
:与 std::lock_guard
不同,std::unique_lock
可以手动解锁、重新加锁,甚至可以延迟加锁。
lock.unlock();
:手动解锁。在需要手动管理锁的复杂场景中,std::unique_lock
更灵活。
C++17还提供了共享锁,感兴趣可以留言。
死锁预防
在多线程程序中,确保锁的获取顺序一致,以防止死锁。避免同时锁定多个互斥锁,或者使用 std::lock
来同时锁定多个 mutex
。
代码示例
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx1, mtx2;
void thread1() {
std::lock(mtx1, mtx2); // 同时锁定多个 mutex,避免死锁
std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
std::cout << "Thread 1 is running\n";
}
void thread2() {
std::lock(mtx1, mtx2); // 同时锁定多个 mutex,避免死锁
std::lock_guard<std::mutex> lock1(mtx1, std::adopt_lock);
std::lock_guard<std::mutex> lock2(mtx2, std::adopt_lock);
std::cout << "Thread 2 is running\n";
}
int main() {
std::thread t1(thread1);
std::thread t2(thread2);
t1.join();
t2.join();
return 0;
}
总结
std::mutex
是 C++11 提供的标准同步机制,保证了线程间对共享资源的互斥访问。
std::lock_guard
和 std::unique_lock
是 RAII 风格的锁定工具,分别适用于简单和复杂的锁定需求。
死锁 可以通过一致的锁定顺序或使用 std::lock
来避免。
2.Linux 下的 Mutex
在 Linux 下,通常使用 POSIX 线程库(pthread
)来实现互斥锁。pthread
提供了 pthread_mutex_t
结构和相关函数来管理互斥锁。
代码示例
#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; // 初始化互斥锁
void* print_numbers(void* arg) {
for (int i = 0; i < 5; ++i) {
pthread_mutex_lock(&mtx); // 加锁
cout << "Thread " << pthread_self() << ": " << i << endl;
pthread_mutex_unlock(&mtx); // 解锁
sleep(1); // 模拟其他操作
}
return nullptr;
}
int main() {
pthread_t t1, t2;
// 创建两个线程
pthread_create(&t1, nullptr, print_numbers, nullptr);
pthread_create(&t2, nullptr, print_numbers, nullptr);
// 等待线程结束
pthread_join(t1, nullptr);
pthread_join(t2, nullptr);
// 销毁互斥锁
pthread_mutex_destroy(&mtx);
return 0;
}
Linux 中的操作
- 初始化互斥锁:使用
pthread_mutex_init()
或PTHREAD_MUTEX_INITIALIZER
来初始化。 - 加锁:使用
pthread_mutex_lock()
。 - 解锁:使用
pthread_mutex_unlock()
。 - 销毁互斥锁:使用
pthread_mutex_destroy()
。
3.Windows 下的 Mutex
在 Windows 下,使用 Windows API
提供的同步原语。常用的有 CreateMutex()
和 WaitForSingleObject()
,它们可以实现互斥锁的功能。此外,Windows 还提供了轻量级的 CRITICAL_SECTION
,这类似于互斥锁,但只在单个进程内使用,效率更高。
使用 Mutex
对象
#include <iostream>
#include <windows.h>
using namespace std;
HANDLE mtx; // 互斥锁句柄
DWORD WINAPI print_numbers(LPVOID arg) {
for (int i = 0; i < 5; ++i) {
WaitForSingleObject(mtx, INFINITE); // 加锁
cout << "Thread " << GetCurrentThreadId() << ": " << i << endl;
ReleaseMutex(mtx); // 解锁
Sleep(1000); // 模拟其他操作
}
return 0;
}
int main() {
// 创建互斥锁对象
mtx = CreateMutex(nullptr, FALSE, nullptr);
// 创建两个线程
HANDLE t1 = CreateThread(nullptr, 0, print_numbers, nullptr, 0, nullptr);
HANDLE t2 = CreateThread(nullptr, 0, print_numbers, nullptr, 0, nullptr);
// 等待线程结束
WaitForSingleObject(t1, INFINITE);
WaitForSingleObject(t2, INFINITE);
// 关闭线程句柄
CloseHandle(t1);
CloseHandle(t2);
// 销毁互斥锁
CloseHandle(mtx);
return 0;
}
Windows 中的操作
- 创建互斥锁:使用
CreateMutex()
。 - 加锁:使用
WaitForSingleObject()
。 - 解锁:使用
ReleaseMutex()
。 - 销毁互斥锁:使用
CloseHandle()
。
4.Windows 下的 CRITICAL_SECTION
CRITICAL_SECTION
是 Windows 提供的轻量级锁,只能用于单个进程内的线程同步,但比 Mutex
更高效。
代码示例
#include <iostream>
#include <windows.h>
using namespace std;
CRITICAL_SECTION cs; // 临界区对象
DWORD WINAPI print_numbers(LPVOID arg) {
for (int i = 0; i < 5; ++i) {
EnterCriticalSection(&cs); // 加锁
cout << "Thread " << GetCurrentThreadId() << ": " << i << endl;
LeaveCriticalSection(&cs); // 解锁
Sleep(1000); // 模拟其他操作
}
return 0;
}
int main() {
// 初始化临界区对象
InitializeCriticalSection(&cs);
// 创建两个线程
HANDLE t1 = CreateThread(nullptr, 0, print_numbers, nullptr, 0, nullptr);
HANDLE t2 = CreateThread(nullptr, 0, print_numbers, nullptr, 0, nullptr);
// 等待线程结束
WaitForSingleObject(t1, INFINITE);
WaitForSingleObject(t2, INFINITE);
// 关闭线程句柄
CloseHandle(t1);
CloseHandle(t2);
// 删除临界区对象
DeleteCriticalSection(&cs);
return 0;
}
总结
std::mutex
是 C++11 提供的标准同步机制,保证了线程间对共享资源的互斥访问。std::lock_guard
和std::unique_lock
是 RAII 风格的锁定工具,分别适用于简单和复杂的锁定需求。
- Linux:使用 POSIX 线程库 (
pthread
) 实现Mutex
。操作包括初始化、加锁、解锁和销毁。 - Windows:使用
CreateMutex()
和WaitForSingleObject()
实现Mutex
,或使用CRITICAL_SECTION
进行更高效的同步。