brpc/include/butil/synchronization/lock.h
2022-12-14 19:05:52 +08:00

168 lines
4.6 KiB
C++

// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#ifndef BUTIL_SYNCHRONIZATION_LOCK_H_
#define BUTIL_SYNCHRONIZATION_LOCK_H_
#include "butil/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
#elif defined(OS_POSIX)
#include <pthread.h>
#endif
#include "butil/base_export.h"
#include "butil/macros.h"
#include "butil/compat.h"
namespace butil {
// A convenient wrapper for an OS specific critical section.
class BUTIL_EXPORT Mutex {
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.
class BUTIL_EXPORT Lock : public Mutex {
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);
};
} // namespace butil
#endif // BUTIL_SYNCHRONIZATION_LOCK_H_