一.互斥锁介绍
互斥锁(mutex)是C++11中用于保护共享资源的一种同步机制,其原理基于以下关键点:
- 独占所有权:
std::mutex
提供独占所有权的特性,即在同一时间只有一个线程能够拥有互斥锁。当一个线程拥有锁时,其他试图锁定该互斥量的线程将会被阻塞,直到锁被释放。- 阻塞等待:如果互斥量已被其他线程锁定,调用
lock()
的线程会进入阻塞状态,等待直到互斥量变为未锁定状态。这种阻塞等待特性可以减少CPU的忙等,提高系统效率。- 防止多线程同时访问:互斥锁的主要目的是防止多个线程同时访问共享资源,避免竞态条件的发生,确保数据的一致性和完整性。
- 允许临界区睡眠:与自旋锁不同,互斥锁在等待锁的时候允许线程进行上下文切换去执行其他任务,或者进入睡眠状态,这有助于提高系统的响应性和吞吐量。
- 不可复制:互斥量对象不允许拷贝构造和赋值操作,以确保程序的正确性。这是因为拷贝或移动互斥量可能会导致多个线程尝试释放同一个互斥量,从而引发错误。
- 解锁必须由锁定的线程执行:谁获取了互斥锁,只有这个线程可以释放它。这意味着互斥锁的生命周期需要仔细管理,以避免死锁或忘记解锁的情况发生。
- 实现细节:互斥锁的具体实现可能依赖于操作系统和编译器。在某些系统中,互斥锁的数量可能受到限制,由宏定义
LOSCFG_BASE_IPC_MUX_LIMIT
指定。- 适用场景:由于互斥锁可能导致线程阻塞和上下文切换,它在内容较多且切换不频繁的情况下较为适用。在需要保护的临界区代码量较大时,使用互斥锁可以防止忙等待,从而提高系统的整体性能。
综上所述,互斥锁在C++11中为多线程编程提供了一种有效的同步手段,通过阻塞等待和非递归锁定来确保共享资源的安全访问。
二.线程共享变量互斥访问的示例代码(使用2个线程去操作共享变量)
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx; // 定义一个全局互斥量
int shared_var = 0; // 定义一个全局共享变量
void thread_function(std::string id) {
for (int i = 0; i < 10; ++i) {
mtx.lock(); // 获取互斥量锁
shared_var++; // 对共享变量进行操作
std::cout << "id: " << id.c_str() <<" shared_var = "<<shared_var<< std::endl;
mtx.unlock(); // 释放互斥量锁
}
}
int main() {
std::thread t1(thread_function,"th1");
std::thread t2(thread_function,"th2");
t1.join();
t2.join();
std::cout << "Shared variable value: " << shared_var << std::endl;
return 0;
}
输出结果:
三. mutex和std::lock_guard的区别
mutex是用来保证线程同步的,防止不同的线程同时操作同一个共享数据。但使用lock_guard则相对安全,它是基于作用域的,能够自解锁,当该对象创建时,它会像m.lock()一样获得互斥锁,当生命周期结束时,它会自动析构(unlock),不会因为某个线程异常退出而影响其他线程。示例
#include <iostream>
#include <thread>
#include <mutex>
int cnt = 10;
std::mutex mtx;
void t1(std::string id)
{
while (cnt > 0)
{
std::lock_guard<std::mutex> lockGuard(mtx);
// std::m.lock();
if (cnt > 0)
{
--cnt;
std::cout <<"id::"<<id.c_str() <<" cnt = "<<cnt << std::endl;
}
// std::m.unlock();
}
}
void t2(std::string id)
{
while (cnt > 0)
{
std::lock_guard<std::mutex> lockGuard(mtx);
// std::m.lock();
if (cnt > 0)
{
--cnt;
std::cout <<"id::"<<id.c_str() <<" cnt = "<< cnt << std::endl;
}
// std::m.unlock();
}
}
int main(void)
{
std::thread th1(t1,"th1");
std::thread th2(t2,"th2");
th1.join(); //等待t1退出
th2.join(); //等待t2退出
std::cout << "here is the main()" << std::endl;
return 0;
}
运行结果: