Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-03-09 04:49:56

0001 #ifndef FWCore_Concurrency_WaitingTask_h
0002 #define FWCore_Concurrency_WaitingTask_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     Concurrency
0006 // Class  :     WaitingTask
0007 //
0008 /**\class WaitingTask WaitingTask.h FWCore/Concurrency/interface/WaitingTask.h
0009 
0010  Description: Task used by WaitingTaskList.
0011 
0012  Usage:
0013     Used as a callback to happen after a task has been completed. Includes the ability to hold an exception which has occurred while waiting.
0014 */
0015 //
0016 // Original Author:  Chris Jones
0017 //         Created:  Thu Feb 21 13:46:31 CST 2013
0018 // $Id$
0019 //
0020 
0021 // system include files
0022 #include <atomic>
0023 #include <exception>
0024 #include <memory>
0025 
0026 // user include files
0027 #include "FWCore/Concurrency/interface/TaskBase.h"
0028 
0029 // forward declarations
0030 
0031 namespace edm {
0032   class WaitingTaskList;
0033   class WaitingTaskHolder;
0034   class WaitingTaskWithArenaHolder;
0035 
0036   class WaitingTask : public TaskBase {
0037   public:
0038     friend class WaitingTaskList;
0039     friend class WaitingTaskHolder;
0040     friend class WaitingTaskWithArenaHolder;
0041 
0042     ///Constructor
0043     WaitingTask() : m_ptr{nullptr} {}
0044     ~WaitingTask() override { delete m_ptr.load(); };
0045 
0046     // ---------- const member functions ---------------------------
0047 
0048     ///Returns exception thrown by dependent task
0049     /** If the value is non-null then the dependent task failed.
0050     */
0051     std::exception_ptr const* exceptionPtr() const { return m_ptr.load(); }
0052 
0053   private:
0054     ///Called if waited for task failed
0055     /**Allows transfer of the exception caused by the dependent task to be
0056      * moved to another thread.
0057      * This method should only be called by WaitingTaskList
0058      */
0059     void dependentTaskFailed(std::exception_ptr iPtr) {
0060       if (iPtr and not m_ptr) {
0061         auto temp = std::make_unique<std::exception_ptr>(iPtr);
0062         std::exception_ptr* expected = nullptr;
0063         if (m_ptr.compare_exchange_strong(expected, temp.get())) {
0064           temp.release();
0065         }
0066       }
0067     }
0068 
0069     std::atomic<std::exception_ptr*> m_ptr;
0070   };
0071 
0072   /** Use this class on the stack to signal the final task to be run.
0073    Call done() to check to see if the task was run and check value of
0074    exceptionPtr() to see if an exception was thrown by any task in the group.
0075    */
0076   class FinalWaitingTask : public WaitingTask {
0077   public:
0078     FinalWaitingTask() : m_done{false} {}
0079 
0080     void execute() final { m_done = true; }
0081 
0082     bool done() const { return m_done.load(); }
0083 
0084   private:
0085     void recycle() final {}
0086     std::atomic<bool> m_done;
0087   };
0088 
0089   template <typename F>
0090   class FunctorWaitingTask : public WaitingTask {
0091   public:
0092     explicit FunctorWaitingTask(F f) : func_(std::move(f)) {}
0093 
0094     void execute() final { func_(exceptionPtr()); };
0095 
0096   private:
0097     F func_;
0098   };
0099 
0100   template <typename F>
0101   FunctorWaitingTask<F>* make_waiting_task(F f) {
0102     return new FunctorWaitingTask<F>(std::move(f));
0103   }
0104 
0105 }  // namespace edm
0106 
0107 #endif