168 lines
4.6 KiB
C++
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_
|