/* * 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_EXECUTORSERVICE_H_ #define _DECAF_UTIL_CONCURRENT_EXECUTORSERVICE_H_ #include #include #include #include #include #include #include #include namespace decaf { namespace util { namespace concurrent { /** * An Executor that provides methods to manage termination and methods that can produce a Future for * tracking progress of one or more asynchronous tasks. * * An ExecutorService can be shut down, which will cause it to reject new tasks. Two different methods * are provided for shutting down an ExecutorService. The shutdown() method will allow previously * submitted tasks to execute before terminating, while the shutdownNow() method prevents waiting tasks * from starting and attempts to stop currently executing tasks. Upon termination, an executor has no * tasks actively executing, no tasks awaiting execution, and no new tasks can be submitted. An unused * ExecutorService should be shut down to allow reclamation of its resources. * * Method submit extends base method Executor.execute(decaf.lang.Runnable) by creating and returning a * Future that can be used to cancel execution and/or wait for completion. Methods invokeAny and invokeAll * perform the most commonly useful forms of bulk execution, executing a collection of tasks and then * waiting for at least one, or all, to complete. (Class ExecutorCompletionService can be used to write * customized variants of these methods.) * * The Executors class provides factory methods for the executor services provided in this package. * * @since 1.0 */ class DECAF_API ExecutorService : public Executor { public: virtual ~ExecutorService() {} /** * The caller will block until the executor has completed termination meaning all tasks * that where scheduled before shutdown have now completed and the executor is ready for * deletion. If the timeout period elapses before the executor reaches the terminated * state then this method return false to indicate it has not terminated. * * @param timeout * The amount of time to wait before abandoning the wait for termination. * @param unit * The unit of time that the timeout value represents. * * @return true if the executor terminated or false if the timeout expired. * * @throws InterruptedException if this call is interrupted while awaiting termination. */ virtual bool awaitTermination(long long timeout, const TimeUnit& unit) = 0; /** * Performs an orderly shutdown of this Executor. Previously queued tasks are allowed * to complete but no new tasks are accepted for execution. Calling this method more * than once has no affect on this executor. */ virtual void shutdown() = 0; /** * Attempts to stop all currently executing tasks and returns an ArrayList containing the * Runnables that did not get executed, these object become the property of the caller and * are not deleted by this class, they are removed from the work queue and forgotten about. * * There is no guarantee that this method will halt execution of currently executing tasks. * * @return an ArrayList containing all Runnable instance that were still waiting to be * executed by this class, call now owns those pointers. */ virtual ArrayList shutdownNow() = 0; /** * Returns whether this executor has been shutdown or not. * * @return true if this executor has been shutdown. */ virtual bool isShutdown() const = 0; /** * Returns whether all tasks have completed after this executor was shut down. * * @return true if all tasks have completed after a request to shut down was made. */ virtual bool isTerminated() const = 0; /** * Submits a value-returning task for execution and returns a Future pointer * representing the pending results of the task. The Future's get method * will return the task's result upon successful completion. The caller owns the * returned pointer and is responsible for deleting it. The returned value is a * proxy to the actual FutureTask that is submitted for execution so is legal for * the caller to delete this value before its execution has completed. * * @param task * Pointer to the Callable task to submit. * @param takeOwnership * Boolean value indicating if the Executor now owns the pointer to the task. * * @return a Future pointer representing pending completion of the task. * * @throws RejectedExecutionException if the task cannot be scheduled for execution * @throws NullPointerException if the task is null */ template Future* submit(Callable* task, bool takeOwnership = true) { // Creates a new FutureTask to wrap the target task, and then creates a clone // that will act as the proxy to return to the caller. Pointer< FutureTask > newTask(new FutureTask(task, takeOwnership)); Pointer< FutureTask > proxy(newTask->clone()); try { // Its safe to submit and allow the task to be executed only after creating // the proxy so that if its run on the current thread and destroyed the // proxy still holds a vlid reference to the inner FutureTask data keeping it // from being destroyed before the caller has a chance to call get(). this->doSubmit(newTask.get()); // No exception so we can release our ref, the executor owns it now. newTask.release(); return proxy.release(); } catch(decaf::util::concurrent::RejectedExecutionException& ex) { // Policy will delete the submitted task newTask.release(); ex.setMark(__FILE__, __LINE__); throw; } DECAF_CATCH_RETHROW(decaf::lang::exceptions::NullPointerException) DECAF_CATCHALL_THROW(decaf::lang::Exception) } /** * Submits a Runnable task for execution and returns a Future representing that * task. The Future's get method will return the given result upon successful * completion. The caller owns the returned pointer and is responsible for deleting it. * The returned value is a proxy to the actual FutureTask that is submitted for execution * so is legal for the caller to delete this value before its execution has completed. * * @param task * The pointer to the task to submit. * @param result * The result to return * @param takeOwnership * Boolean value indicating if the Executor now owns the pointer to the task. * * @return a Future pointer representing pending completion of the task, * * @throws RejectedExecutionException if the task cannot be scheduled for execution * @throws NullPointerException if the task is null */ template Future* submit(decaf::lang::Runnable* task, const E& result, bool takeOwnership = true) { // Creates a new FutureTask to wrap the target task, and then creates a clone // that will act as the proxy to return to the caller. Pointer< FutureTask > newTask(new FutureTask(task, result, takeOwnership)); Pointer< FutureTask > proxy(newTask->clone()); try { // Its safe to submit and allow the task to be executed only after creating // the proxy so that if its run on the current thread and destroyed the // proxy still holds a vlid reference to the inner FutureTask data keeping it // from being destroyed before the caller has a chance to call get(). this->doSubmit(newTask.get()); // No exception so we can release our reference, the executor owns it now. newTask.release(); return proxy.release(); } catch(decaf::util::concurrent::RejectedExecutionException& ex) { // Policy will delete the submitted task newTask.release(); ex.setMark(__FILE__, __LINE__); throw; } DECAF_CATCH_RETHROW(decaf::lang::exceptions::NullPointerException) DECAF_CATCHALL_THROW(decaf::lang::Exception) } /** * Submits a Runnable object for execution. A Future object is created and returned * that will return the default value of the template type upon completion. The caller * owns the returned pointer and is responsible for deleting it. The returned value is * a proxy to the actual FutureTask that is submitted for execution so is legal for the * caller to delete this value before its execution has completed. * * @param task * Pointer to a Runnable object that will be executed by this ExecutorService. * @param takeOwnership * Boolean value indicating if the Executor now owns the pointer to the task. * * @returns a new Future pointer that is owned by the caller. * * @throws RejectedExecutionException if the task cannot be scheduled for execution * @throws NullPointerException if the Runnable pointer passed is NULL. */ template Future* submit(decaf::lang::Runnable* task, bool takeOwnership = true) { // Creates a new FutureTask to wrap the target task, and then creates a clone // that will act as the proxy to return to the caller. Pointer< FutureTask > newTask(new FutureTask(task, E(), takeOwnership)); Pointer< FutureTask > proxy(newTask->clone()); try { // Its safe to submit and allow the task to be executed only after creating // the proxy so that if its run on the current thread and destroyed the // proxy still holds a vlid reference to the inner FutureTask data keeping it // from being destroyed before the caller has a chance to call get(). this->doSubmit(newTask.get()); // No exception so we can release our ref, the executor owns it now. newTask.release(); return proxy.release(); } catch(decaf::util::concurrent::RejectedExecutionException& ex) { // Policy will delete the submitted task newTask.release(); ex.setMark(__FILE__, __LINE__); throw; } DECAF_CATCH_RETHROW(decaf::lang::exceptions::NullPointerException) DECAF_CATCHALL_THROW(decaf::lang::Exception) } protected: /** * Perform the actual submit of a FutureType instance, the caller is responsible for * creating the properly typed Future object and returning that to its caller. The * pointer provided is the property of this Executor and must be deleted by this executor * once its completed. * * @param future * Pointer to a base FutureType instance that is to be submitted to the Executor. */ virtual void doSubmit(FutureType* future) = 0; }; }}} #endif /* _DECAF_UTIL_CONCURRENT_EXECUTORSERVICE_H_ */