lock.h 3.9 KB
Newer Older
gejun's avatar
gejun committed
1
// Copyright (c) 2017 Baidu, Inc
gejun's avatar
gejun committed
2 3
// Date: Thu Jan 19 16:19:30 CST 2017

4 5
#ifndef BUTIL_SYNCHRONIZATION_LOCK_H_
#define BUTIL_SYNCHRONIZATION_LOCK_H_
gejun's avatar
gejun committed
6

7
#include "butil/build_config.h"
gejun's avatar
gejun committed
8 9 10 11 12 13
#if defined(OS_WIN)
#include <windows.h>
#elif defined(OS_POSIX)
#include <pthread.h>
#endif

14 15
#include "butil/base_export.h"
#include "butil/macros.h"
gejun's avatar
gejun committed
16

17
namespace butil {
gejun's avatar
gejun committed
18 19

// A convenient wrapper for an OS specific critical section.  
20
class BUTIL_EXPORT Mutex {
gejun's avatar
gejun committed
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
    DISALLOW_COPY_AND_ASSIGN(Mutex);
public:
#if defined(OS_WIN)
  typedef CRITICAL_SECTION NativeHandle;
#elif defined(OS_POSIX)
  typedef pthread_mutex_t NativeHandle;
#endif

public:
    Mutex() {
#if defined(OS_WIN)
    // The second parameter is the spin count, for short-held locks it avoid the
    // contending thread from going to sleep which helps performance greatly.
        ::InitializeCriticalSectionAndSpinCount(&_native_handle, 2000);
#elif defined(OS_POSIX)
        pthread_mutex_init(&_native_handle, NULL);
#endif
    }
    
    ~Mutex() {
#if defined(OS_WIN)
        ::DeleteCriticalSection(&_native_handle);
#elif defined(OS_POSIX)
        pthread_mutex_destroy(&_native_handle);
#endif
    }

    // Locks the mutex. If another thread has already locked the mutex, a call
    // to lock will block execution until the lock is acquired.
    void lock() {
#if defined(OS_WIN)
        ::EnterCriticalSection(&_native_handle);
#elif defined(OS_POSIX)
        pthread_mutex_lock(&_native_handle);
#endif
    }

    // Unlocks the mutex. The mutex must be locked by the current thread of
    // execution, otherwise, the behavior is undefined.
    void unlock() {
#if defined(OS_WIN)
        ::LeaveCriticalSection(&_native_handle);
#elif defined(OS_POSIX)
        pthread_mutex_unlock(&_native_handle);
#endif
    }
    
    // Tries to lock the mutex. Returns immediately.
    // On successful lock acquisition returns true, otherwise returns false.
    bool try_lock() {
#if defined(OS_WIN)
        return (::TryEnterCriticalSection(&_native_handle) != FALSE);
#elif defined(OS_POSIX)
        return pthread_mutex_trylock(&_native_handle) == 0;
#endif
    }

    // Returns the underlying implementation-defined native handle object.
    NativeHandle* native_handle() { return &_native_handle; }

private:
#if defined(OS_POSIX)
    // The posix implementation of ConditionVariable needs to be able
    // to see our lock and tweak our debugging counters, as it releases
    // and acquires locks inside of pthread_cond_{timed,}wait.
friend class ConditionVariable;
#elif defined(OS_WIN)
// The Windows Vista implementation of ConditionVariable needs the
// native handle of the critical section.
friend class WinVistaCondVar;
#endif

    NativeHandle _native_handle;
};

// TODO: Remove this type.
97
class BUTIL_EXPORT Lock : public Mutex {
gejun's avatar
gejun committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    DISALLOW_COPY_AND_ASSIGN(Lock);
public:
    Lock() {}
    ~Lock() {}
    void Acquire() { lock(); }
    void Release() { unlock(); }
    bool Try() { return try_lock(); }
    void AssertAcquired() const {}
};

// A helper class that acquires the given Lock while the AutoLock is in scope.
class AutoLock {
public:
    struct AlreadyAcquired {};

    explicit AutoLock(Lock& lock) : lock_(lock) {
        lock_.Acquire();
    }

    AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) {
        lock_.AssertAcquired();
    }

    ~AutoLock() {
        lock_.AssertAcquired();
        lock_.Release();
    }

private:
    Lock& lock_;
    DISALLOW_COPY_AND_ASSIGN(AutoLock);
};

// AutoUnlock is a helper that will Release() the |lock| argument in the
// constructor, and re-Acquire() it in the destructor.
class AutoUnlock {
public:
    explicit AutoUnlock(Lock& lock) : lock_(lock) {
        // We require our caller to have the lock.
        lock_.AssertAcquired();
        lock_.Release();
    }

    ~AutoUnlock() {
        lock_.Acquire();
    }

private:
    Lock& lock_;
    DISALLOW_COPY_AND_ASSIGN(AutoUnlock);
};

150
}  // namespace butil
gejun's avatar
gejun committed
151

152
#endif  // BUTIL_SYNCHRONIZATION_LOCK_H_