C++\MFC锁lock从专家到小白

C++ mutex

# include <mutex>
std::mutex m_lock;
void CMainWnd::function()
{
    
    
    std::lock_guard<std::mutex> lock(m_lock);
    ...
}
  1. 仅限同一进程内
  2. 阻塞等待:当线程 A 持有锁时,线程 B 尝试获取同一互斥锁时,会进入阻塞状态(除非使用 try_lock),直到线程 A 释放锁。
  3. 独占性:std::mutex 是独占锁,同一时间只允许一个线程持有锁。
  4. 不可重入:同一线程重复获取 std::mutex 会导致死锁(需使用 std::recursive_mutex 实现可重入)。

RALL

std::lock_guard是一个用于管理互斥锁的RAII(资源获取即初始化)类。
RAII:在对象构造时获取资源,在对象析构时释放资源。
当创建一个lock_guard对象时,它会自动锁定给定的互斥量m_lock,而当这个lock_guard对象离开其作用域时,会自动释放互斥量。在离开作用域时自动释放锁,无需手动干预,保证了资源管理的安全性和简洁性。这种设计避免了忘记释放锁或异常导致的死锁问题,是C++中管理互斥锁的首选方式。

释放锁的时机和方式

​1. 作用域结束释放。
2. 异常安全。若临界区代码抛出异常,栈展开会触发 lock_guard 析构,确保锁被释放,避免死锁。
3. 显式作用域控制。通过代码块{}可提前释放锁,缩短持有锁的时间。
4. 多返回点保证。函数中有多个 return 语句,lock_guard 也会在函数返回前析构,确保锁被释放。

try_lock()

try_lock_for(timeout)

MFC

CCriticalSection

CCriticalSection m_cs;
void ThreadSafeFunction() 
{
    
    
    m_cs.Lock();    // 阻塞等待锁
    // 临界区操作(访问共享资源)
    m_cs.Unlock();  // 必须手动解锁!
}

允许同一线程多次调用 Lock() 方法(即支持递归锁/可重入锁)。
CCriticalSection 内部维护一个计数器,记录当前线程持有锁的次数。
只有当计数器归零时,锁才会真正释放,允许其他线程获取。

CMutex

必须手动解锁。

CMutex  m_Mutex;
void CMainWnd::function()
{
    
    
	m_Mutex.Lock();
	// 临界区操作
	m_Mutex.Unlock();
}

使用 CSingleLock 自动管理

析构时自动调用 Unlock()。

CSingleLock lock(&mutex);
lock.Lock();
if (lock.IsLocked()) 
{
    
    
    // 临界区操作
} //析构时自动调用 Unlock()

非阻塞模式

CSingleLock lock(&mutex);
if (lock.Lock(0)) {
    
      // 参数为超时时间(毫秒),0 表示立即返回
    // 成功获取锁
} else {
    
    
    // 锁被占用,执行其他逻辑
}

跨进程同步:命名互斥体

// 进程 A
CMutex mutexA(FALSE, _T("Global\\MyMutex"));  // 注意 "Global\\" 前缀确保系统级可见性
CSingleLock lockA(&mutexA);
lockA.Lock();
// 操作共享资源...

// 进程 B
CMutex mutexB(FALSE, _T("Global\\MyMutex"));
CSingleLock lockB(&mutexB);
lockB.Lock();
// 操作同一共享资源...