From 4e19f1914e49db4b7913ff0f5af8eec51caee875 Mon Sep 17 00:00:00 2001 From: David Reiss Date: Tue, 9 Mar 2010 05:19:59 +0000 Subject: [PATCH] cpp: non-blocking add for ThreadManager It's rare for the ThreadManager mutex to be contended, but it is possible. For nonblocking applications, it is necessary to have a strict timeout for the lock acquisition. With this change, that timeout is enforced. Also add timeout parameters to Mutex::lock and Guard::Guard to support this feature. git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@920679 13f79535-47bb-0310-9956-ffa450edef68 --- lib/cpp/src/concurrency/Mutex.cpp | 9 ++++++++ lib/cpp/src/concurrency/Mutex.h | 26 ++++++++++++++++++----- lib/cpp/src/concurrency/ThreadManager.cpp | 6 +++++- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/lib/cpp/src/concurrency/Mutex.cpp b/lib/cpp/src/concurrency/Mutex.cpp index 5d33c114..67d7a2cb 100644 --- a/lib/cpp/src/concurrency/Mutex.cpp +++ b/lib/cpp/src/concurrency/Mutex.cpp @@ -18,6 +18,7 @@ */ #include "Mutex.h" +#include "Util.h" #include #include @@ -50,6 +51,12 @@ class Mutex::impl { bool trylock() const { return (0 == pthread_mutex_trylock(&pthread_mutex_)); } + bool timedlock(int64_t milliseconds) const { + struct timespec ts; + Util::toTimespec(ts, milliseconds); + return (0 == pthread_mutex_timedlock(&pthread_mutex_, &ts)); + } + void unlock() const { pthread_mutex_unlock(&pthread_mutex_); } void* getUnderlyingImpl() const { return (void*) &pthread_mutex_; } @@ -67,6 +74,8 @@ void Mutex::lock() const { impl_->lock(); } bool Mutex::trylock() const { return impl_->trylock(); } +bool Mutex::timedlock(int64_t ms) const { return impl_->timedlock(ms); } + void Mutex::unlock() const { impl_->unlock(); } void Mutex::DEFAULT_INITIALIZER(void* arg) { diff --git a/lib/cpp/src/concurrency/Mutex.h b/lib/cpp/src/concurrency/Mutex.h index a33b9952..94eb8354 100644 --- a/lib/cpp/src/concurrency/Mutex.h +++ b/lib/cpp/src/concurrency/Mutex.h @@ -37,6 +37,7 @@ class Mutex { virtual ~Mutex() {} virtual void lock() const; virtual bool trylock() const; + virtual bool timedlock(int64_t milliseconds) const; virtual void unlock() const; void* getUnderlyingImpl() const; @@ -75,18 +76,33 @@ private: class Guard { public: - Guard(const Mutex& value) : mutex_(value) { - mutex_.lock(); + Guard(const Mutex& value, int64_t timeout = 0) : mutex_(&value) { + if (timeout == 0) { + value.lock(); + } else if (timeout < 0) { + if (!value.trylock()) { + mutex_ = NULL; + } + } else { + if (!value.timedlock(timeout)) { + mutex_ = NULL; + } + } } ~Guard() { - mutex_.unlock(); + if (mutex_) { + mutex_->unlock(); + } + } + + operator bool() const { + return (mutex_ != NULL); } private: - const Mutex& mutex_; + const Mutex* mutex_; }; - // Can be used as second argument to RWGuard to make code more readable // as to whether we're doing acquireRead() or acquireWrite(). enum RWGuardType { diff --git a/lib/cpp/src/concurrency/ThreadManager.cpp b/lib/cpp/src/concurrency/ThreadManager.cpp index a02ad742..d0bb41f5 100644 --- a/lib/cpp/src/concurrency/ThreadManager.cpp +++ b/lib/cpp/src/concurrency/ThreadManager.cpp @@ -461,7 +461,11 @@ void ThreadManager::Impl::removeWorker(size_t value) { void ThreadManager::Impl::add(shared_ptr value, int64_t timeout, int64_t expiration) { - Guard g(mutex_); + Guard g(mutex_, timeout); + + if (!g) { + throw TimedOutException(); + } if (state_ != ThreadManager::STARTED) { throw IllegalStateException(); -- 2.17.1