/* * 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 _DECAF_UTIL_CONCURRENT_LOCKSUPPORT_H_ #define _DECAF_UTIL_CONCURRENT_LOCKSUPPORT_H_ #include namespace decaf { namespace lang{ class Thread; } namespace util { namespace concurrent { namespace locks { /** * Basic thread blocking primitives for creating locks and other synchronization classes. * * This class associates, with each thread that uses it, a permit (in the sense of the * Semaphore class). A call to park will return immediately if the permit is available, * consuming it in the process; otherwise it may block. A call to unpark makes the permit * available, if it was not already available. (Unlike with Semaphores though, permits do * not accumulate. There is at most one.) * * Methods park and unpark provide efficient means of blocking and unblocking threads * Races between one thread invoking park and another thread trying to unpark it will * preserve liveness, due to the permit. Additionally, park will return if the caller's * thread was interrupted, and timeout versions are supported. The park method may also * return at any other time, for "no reason", so in general must be invoked within a loop * that rechecks conditions upon return. In this sense park serves as an optimization of a * "busy wait" that does not waste as much time spinning, but must be paired with an unpark * to be effective. * * These methods are designed to be used as tools for creating higher-level synchronization * utilities, and are not in themselves useful for most concurrency control applications. * The park method is designed for use only in constructions of the form: * * while (!canProceed()) { ... LockSupport.park(this); } * * where neither canProceed nor any other actions prior to the call to park entail locking or * blocking. Because only one permit is associated with each thread, any intermediary uses of * park could interfere with its intended effects. * * Sample Usage. Here is a sketch of a first-in-first-out non-reentrant lock class: * * class FIFOMutex { * private: * * AtomicBoolean locked; * ConcurrentLinkedQueue waiters; * * public: * * void lock() { * * bool wasInterrupted = false; * Thread* current = Thread::currentThread(); * waiters.add( current ); * * // Block while not first in queue or cannot acquire lock * while( waiters.peek() != current || * !locked.compareAndSet( false, true ) ) { * * LockSupport.park(this); * if( Thread::interrupted() ) // ignore interrupts while waiting * wasInterrupted = true; * } * * waiters.remove(); * if( wasInterrupted ) // reassert interrupt status on exit * current.interrupt(); * } * * void unlock() { * locked.set( false ); * LockSupport.unpark( waiters.peek() ); * } * }; * * @since 1.0 */ class DECAF_API LockSupport { private: LockSupport(); public: ~LockSupport(); /** * Makes available the permit for the given thread, if it was not already available. If * the thread was blocked on park then it will unblock. Otherwise, its next call to park * is guaranteed not to block. This operation is not guaranteed to have any effect at all * if the given thread has not been started. * * @param thread the thread to unport, or NULL in which case the method has no effect. */ static void unpark( decaf::lang::Thread* thread ); /** * Disables the current thread for thread scheduling purposes unless the permit is available. * * If the permit is available then it is consumed and the call returns immediately; otherwise * the current thread becomes disabled for thread scheduling purposes and lies dormant until * one of three things happens: * * * Some other thread invokes unpark with the current thread as the target; or * * Some other thread interrupts the current thread; or * * The call spuriously (that is, for no reason) returns. * * This method does not report which of these caused the method to return. Callers should * re-check the conditions which caused the thread to park in the first place. Callers may * also determine, for example, the interrupt status of the thread upon return. */ static void park(); /** * Disables the current thread for thread scheduling purposes, for up to the specified * waiting time, unless the permit is available. * * If the permit is available then it is consumed and the call returns immediately; * otherwise the current thread becomes disabled for thread scheduling purposes and lies * dormant until one of four things happens: * * * Some other thread invokes unpark with the current thread as the target; or * * Some other thread interrupts the current thread; or * * The specified waiting time elapses; or * * The call spuriously (that is, for no reason) returns. * * This method does not report which of these caused the method to return. Callers should * re-check the conditions which caused the thread to park in the first place. Callers may * also determine, for example, the interrupt status of the thread, or the elapsed time * upon return. * * @param nanos the maximum number of nanoseconds to wait */ static void parkNanos( long long nanos ); /** * Disables the current thread for thread scheduling purposes, until the specified deadline, * unless the permit is available. * * If the permit is available then it is consumed and the call returns immediately; otherwise * the current thread becomes disabled for thread scheduling purposes and lies dormant until * one of four things happens: * * * Some other thread invokes unpark with the current thread as the target; or * * Some other thread interrupts the current thread; or * * The specified deadline passes; or * * The call spuriously (that is, for no reason) returns. * * This method does not report which of these caused the method to return. Callers should * re-check the conditions which caused the thread to park in the first place. Callers may * also determine, for example, the interrupt status of the thread, or the current time * upon return. * * @param deadline the absolute time, in milliseconds from the Epoch, to wait until */ static void parkUntil( long long deadline ); }; }}}} #endif /* _DECAF_UTIL_CONCURRENT_LOCKSUPPORT_H_ */