简单实现一个lock

import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.LockSupport;

import sun.misc.Unsafe;

public class MyLock {
    private static Unsafe unsafe;

    /**
     * 当前加锁状态,记录加锁的次数
     */
    private volatile int state = 0;

    /**
     * 当前持有锁的线程
     */
    private Thread lockHolder;

    static  {
        Field theUnsafe = null;
        try {
            theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        theUnsafe.setAccessible(true);
        try {
            unsafe = (Unsafe) theUnsafe.get(null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    private static final long stateOffset;

    static {
        try {
            stateOffset = unsafe.objectFieldOffset(MyLock.class.getDeclaredField("state"));
        } catch (NoSuchFieldException e) {
            throw new Error();
        }
    }

    // 等待队列
    private static ConcurrentLinkedQueue <Thread> queue = new ConcurrentLinkedQueue<>();

    public static Unsafe getUnsafe() {
        return unsafe;
    }

    public static void setUnsafe(Unsafe unsafe) {
        MyLock.unsafe = unsafe;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public Thread getLockHolder() {
        return lockHolder;
    }

    public void setLockHolder(Thread lockHolder) {
        this.lockHolder = lockHolder;
    }

    public static long getStateOffset() {
        return stateOffset;
    }

    public final boolean compareAndSwapState(int oldValue, int newValue) {
        return unsafe.compareAndSwapInt(this, stateOffset, oldValue, newValue);

    }

    private boolean tryAquire() {
        int state = getState();
        if (state == 0) {
            // 可以加
            if ((queue.size() == 0 || queue.peek() == Thread.currentThread()) //为0和,判断是否是队列的头部。
                && compareAndSwapState(0, 1)) {
                lockHolder = Thread.currentThread();
                return true;
            }
        }
        return false;
    }

    public void lock() {
        // 获取锁,CAS
        if (tryAquire()) {
            return;
        }
        Thread current = Thread.currentThread();
        queue.add(current);
        // 停留在当前方法
        while (true) {
            // 队列头先获取
            if (queue.peek() == current && tryAquire()) {
                System.out.println("hold lock thread-name" + current.getName());
                return;
            }
            // 阻塞线程
            LockSupport.park(current);

        }

        // 锁释放后,再次获得
    }

    public void unlock() {
        // 不合法的
        if (queue.peek() != Thread.currentThread()) {
            throw new RuntimeException();
        }

        Thread current = Thread.currentThread();
        int state = getState();
        if (compareAndSwapState(1, 0)) {
            System.out.println("hold lock thread-name" + current.getName() + " 释放成功");
            setLockHolder(null);
            Thread headThread = queue.peek();
            if (headThread != null) {
                // 解开阻塞。
                LockSupport.unpark(headThread);
            }
        }
    }
}

<think> 我们需要实现一个MutexLock类,它继承自ILock接口,使用互斥量(Mutex)作为同步原语。在Windows环境下,我们可以使用`CreateMutex`等API,但为了通用性,这里使用Windows的互斥对象(HANDLE类型)。同时,我们将遵循RAII原则,在构造函数中创建互斥量,在析构函数中关闭句柄。 注意:由于ILock一个抽象基类,所以我们必须实现所有的纯虚函数(Lock, TryLock, UnLock)。 以下是MutexLock类的实现: ```cpp #include <windows.h> class MutexLock : public ILock { public: MutexLock() : m_hMutex(NULL) { // 创建匿名互斥量,初始状态为未锁定 m_hMutex = CreateMutex( NULL, // 默认安全属性 FALSE, // 初始状态:FALSE表示未锁定(即创建后为可获取状态) NULL // 匿名互斥量 ); if (m_hMutex == NULL) { // 创建失败,抛出异常 throw "Failed to create mutex"; } } virtual ~MutexLock() { if (m_hMutex != NULL) { CloseHandle(m_hMutex); m_hMutex = NULL; } } virtual void Lock(void) override { // 无限等待直到获取到互斥量 DWORD dwWaitResult = WaitForSingleObject(m_hMutex, INFINITE); if (dwWaitResult != WAIT_OBJECT_0) { // 等待失败,可以抛出异常或者处理错误 throw "Failed to lock mutex"; } } virtual bool TryLock(void) override { // 尝试立即获取互斥量,不等待 DWORD dwWaitResult = WaitForSingleObject(m_hMutex, 0); if (dwWaitResult == WAIT_OBJECT_0) { return true; } // 如果超时(即无法立即获取)或者出错,返回false return false; } virtual void UnLock(void) override { if (!ReleaseMutex(m_hMutex)) { // 释放失败,处理错误 throw "Failed to unlock mutex"; } } protected: HANDLE m_hMutex; }; ``` ### 解释: 1. **构造函数**:使用`CreateMutex`创建一个互斥量句柄。如果创建失败(返回NULL),则抛出异常。 2. **析构函数**:关闭互斥量句柄,防止资源泄漏。 3. **Lock函数**:调用`WaitForSingleObject`并设置INFINITE等待时间,直到获取互斥量。如果等待失败(返回值不是WAIT_OBJECT_0),则抛出异常。 4. **TryLock函数**:调用`WaitForSingleObject`并设置0毫秒超时,立即返回。如果获取到互斥量(返回WAIT_OBJECT_0),则返回true;否则返回false。 5. **UnLock函数**:调用`ReleaseMutex`释放互斥量。如果释放失败,则抛出异常。 ### 注意: - 异常处理:这里使用了简单的字符串异常,实际应用中应该定义更具体的异常类型。 - 跨平台:这个实现只适用于Windows。如果要跨平台,需要使用条件编译或抽象工厂模式。 ### 改进建议: 1. **禁用拷贝和赋值**:互斥量句柄是资源,应该禁止拷贝和赋值,避免重复释放。 ```cpp MutexLock(const MutexLock&) = delete; MutexLock& operator=(const MutexLock&) = delete; ``` 2. **移动语义**:如果需要,可以支持移动构造函数和移动赋值操作符,以便在容器中存放或转移所有权。 3. **更健壮的错误处理**:使用更详细的异常信息,例如通过`GetLastError()`获取错误码。 §§相关问题§§: 1. 在Windows中,互斥量(Mutex)和临界区(Critical Section)的主要区别是什么? 2. 为什么在MutexLock的析构函数中需要检查m_hMutex是否为NULL? 3. 在Lock函数中,除了WAIT_OBJECT_0,还有哪些可能的返回值?应如何处理? 4. 如何使MutexLock类支持跨平台(例如Linux)? </think> ### 实现 `MutexLock` 类 以下是基于 Windows API 实现的 `MutexLock` 类,它继承自 `ILock` 接口: ```cpp #include <windows.h> class MutexLock : public ILock { public: MutexLock() : m_hMutex(NULL) { // 创建匿名互斥体 (无名称) m_hMutex = CreateMutex( NULL, // 默认安全属性 FALSE, // 初始状态:FALSE = 未锁定 NULL // 匿名互斥体 ); if (!m_hMutex) { throw std::runtime_error("Mutex creation failed"); } } virtual ~MutexLock() { if (m_hMutex) { CloseHandle(m_hMutex); } } // 禁用拷贝和赋值 MutexLock(const MutexLock&) = delete; MutexLock& operator=(const MutexLock&) = delete; virtual void Lock() override { DWORD result = WaitForSingleObject(m_hMutex, INFINITE); if (result != WAIT_OBJECT_0) { throw std::runtime_error("Mutex lock failed"); } } virtual bool TryLock() override { DWORD result = WaitForSingleObject(m_hMutex, 0); return (result == WAIT_OBJECT_0); } virtual void UnLock() override { if (!ReleaseMutex(m_hMutex)) { throw std::runtime_error("Mutex unlock failed"); } } private: HANDLE m_hMutex; }; ``` ### 关键实现解析 1. **构造函数初始化** ```cpp m_hMutex = CreateMutex(NULL, FALSE, NULL); ``` - 创建未命名的互斥体对象 - `FALSE` 表示初始状态未锁定 - 错误时抛出异常 2. **RAII 资源管理** ```cpp virtual ~MutexLock() { if (m_hMutex) CloseHandle(m_hMutex); } ``` - 确保互斥体句柄在对象生命周期结束时释放 - 避免资源泄漏 3. **线程安全操作** - `Lock()`: 无限等待获取互斥体 ```cpp WaitForSingleObject(m_hMutex, INFINITE); ``` - `TryLock()`: 非阻塞尝试获取 ```cpp WaitForSingleObject(m_hMutex, 0); ``` - `UnLock()`: 释放互斥体所有权 ```cpp ReleaseMutex(m_hMutex); ``` 4. **异常安全** - 所有操作失败时抛出标准异常 - 提供清晰的错误信息 ### 与 `NLock` 的对比 | 特性 | `NLock` (临界区) | `MutexLock` (互斥体) | |---------------------|-------------------------------|------------------------------| | 作用范围 | 进程内线程同步 | 跨进程线程同步 | | 性能 | 更高 (用户态操作) | 较低 (需内核切换) | | 递归锁 | 支持 | 支持 | | 超时机制 | 无 | 支持 (TryLock) | | 错误处理 | 依赖返回值 | 异常机制 | | 适用场景 | 高性能进程内同步 | 跨进程共享资源保护 | ### 使用示例 ```cpp void SafeDataAccess(ILock& lock) { std::lock_guard<ILock> guard(lock); // C++17 可推导模板参数 // 安全访问共享资源 } int main() { MutexLock globalLock; std::thread t1(SafeDataAccess, std::ref(globalLock)); std::thread t2(SafeDataAccess, std::ref(globalLock)); t1.join(); t2.join(); } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值