互斥(Mutual Exclusion)详解

互斥 (Mutual Exclusion)是指在并发编程中,确保多个线程或进程在访问共享资源(如内存、文件或设备)时,不会同时进行操作的机制。通过互斥,可以避免资源竞争和数据不一致的问题。

互斥的核心思想

互斥的核心是在同一时刻只允许一个线程或进程访问共享资源。当一个线程在访问共享资源时,其他线程必须等待,直到该线程完成访问并释放互斥锁。

互斥的实现方式

常见的互斥实现方式包括:

1. 互斥锁(Mutex)

互斥锁是一种同步原语,用于在线程之间保护共享资源。

  • 加锁(Locking):在访问共享资源前获取锁。
  • 解锁(Unlocking):在访问结束后释放锁。

代码实现:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx;  // 互斥锁
int shared_data = 0;

void increment() {
    for (int i = 0; i < 100; ++i) {
        mtx.lock();  // 加锁
        ++shared_data;
        mtx.unlock();  // 解锁
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Final value of shared_data: " << shared_data << std::endl;
    return 0;
}

输出:

Final value of shared_data: 200

如果没有互斥锁,多个线程可能同时修改 shared_data,导致结果不正确。

2. 读写锁(Reader-Writer Lock)

在一些场景下,读操作不会改变资源的状态,因此可以允许多个线程同时读取,但写操作需要独占资源。读写锁可以提高效率。

  • 多个线程可以同时读取资源。
  • 只有写线程可以独占访问资源,且写时禁止其他线程读或写。

代码示例:

#include <iostream>
#include <shared_mutex>
#include <thread>

std::shared_mutex rw_lock;  // 读写锁
int shared_data = 0;

void reader() {
    rw_lock.lock_shared();
    std::cout << "Read shared_data: " << shared_data << std::endl;
    rw_lock.unlock_shared();
}

void writer() {
    rw_lock.lock();
    ++shared_data;
    std::cout << "Write shared_data: " << shared_data << std::endl;
    rw_lock.unlock();
}

int main() {
    std::thread t1(writer);
    std::thread t2(reader);
    std::thread t3(reader);

    t1.join();
    t2.join();
    t3.join();

    return 0;
}

3. 信号量(Semaphore)

信号量是一种计数器,用于限制同时访问共享资源的线程数量。

  • 二进制信号量:类似互斥锁,用于单一访问控制。
  • 计数信号量:限制资源的最大并发访问数。

代码示例:

#include <iostream>
#include <thread>
#include <semaphore>

std::counting_semaphore<2> sem(2);  // 允许最多两个线程同时访问
int shared_data = 0;

void task(int id) {
    sem.acquire();  // 获取信号量
    ++shared_data;
    std::cout << "Thread " << id << " incremented shared_data to " << shared_data << std::endl;
    sem.release();  // 释放信号量
}

int main() {
    std::thread t1(task, 1);
    std::thread t2(task, 2);
    std::thread t3(task, 3);

    t1.join();
    t2.join();
    t3.join();

    return 0;
}

互斥中的常见问题

  1. 死锁(Deadlock)
    死锁是指多个线程在等待彼此持有的锁,导致程序无法继续运行的现象。
  • 产生条件:
    1. 互斥:资源只能被一个线程占用。
    2. 请求与保持:一个线程已持有资源,但在等待其他资源时不释放已持有的资源。
    3. 不可抢占:资源不可强制剥夺。
    4. 循环等待:线程间形成资源的循环等待关系。

解决方案

  • 避免嵌套锁。
  • 遵循固定的锁定顺序。
  • 使用死锁检测机制。
  1. 饥饿(Starvation)
    饥饿是指某些线程长期无法获取锁,导致其任务无法执行。

解决方案:

  • 使用公平锁(Fair Lock),确保线程按顺序获取锁。
  1. 优先级反转(Priority Inversion)
    优先级反转是指高优先级线程等待低优先级线程释放锁,而低优先级线程又被中优先级线程占用资源的情况。

解决方案

  • 使用优先级继承(Priority Inheritance)机制。

总结
互斥是并发编程中保护共享资源的关键机制。通过互斥锁、读写锁、信号量等工具,可以有效地避免资源竞争和数据不一致的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值