Salome HOME
5fc75c9d0298ec9c56b1e47871df3a2d2a61cd82
[modules/yacs.git] / src / bases / AlternateThreadPT.hxx
1 // Copyright (C) 2006-2023  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 #ifndef __ALTERNATETHREADPT_HXX__
20 #define __ALTERNATETHREADPT_HXX__
21
22 #include <pthread.h>
23
24 #include "YACSBasesExport.hxx"
25
26 namespace YACS
27 {
28   namespace BASES
29   {
30     //! This class provides a mechanism to run two threads alternately.
31     /*!
32      * Alternate threads can be necessary when two pieces of code must run alternately
33      * and communicate but are difficult or impossible to synchronize explicitly
34      * (e.g. asynchronous algorithms in optimizer loop). This class guarantees that the
35      * two threads NEVER run concurrently, so no lock mechanism is necessary when sharing
36      * data between them.
37      *
38      * The two threads are called "master thread" and "slave thread". The master thread is
39      * the one that calls the method start() and that will continue to run after the
40      * destruction of this object. The slave thread is created when the method start() is
41      * called. It will run the code in the method run() and will be destroyed when the
42      * master thread calls terminateSlaveThread() or at the destruction of this object.
43      *
44      * When the master thread calls start(), it will block and the slave thread will begin
45      * to execute the code in the method run(). The two threads can then alternate by
46      * calling the method signalMasterAndWait() (in the slave thread) and signalSlaveAndWait()
47      * (in the master thread). Finally, the master thread must call terminateSlaveThread()
48      * to terminate the slave thread. There is no explicit mechanism for the slave thread to
49      * request its own termination, but this can be done with an external flag (see the pool
50      * object in OptimizerLoop for instance).
51      *
52      * This class is purely virtual. Subclasses must implement the run() method that will
53      * be executed in the slave thread.
54      */
55     class YACSBASES_EXPORT AlternateThreadPT
56     {
57     public:
58       enum ThreadStatus {UNEXISTING, NORMAL_CYCLE, TERMINATION_REQUESTED, READY_TO_JOIN};
59
60       AlternateThreadPT();
61       virtual ~AlternateThreadPT();
62
63       //! Create and launch the slave thread.
64       /*!
65        * This method must not be called by the slave thread or
66        * if a slave thread is already running.
67        */
68       void start();
69
70       //! Block the master thread and release the slave thread.
71       virtual void signalSlaveAndWait();
72
73       //! Terminate the slave thread.
74       void terminateSlaveThread();
75
76       //! Block the slave thread and release the master thread.
77       virtual void signalMasterAndWait();
78
79       //! Return true if the master requested the slave thread termination.
80       bool isTerminationRequested() const;
81
82       //! Return the thread status.
83       ThreadStatus getThreadStatus() const;
84
85     protected:
86       //! This method must be implemented in subclasses and will be run in the slave thread.
87       /*!
88        * The slave thread must call signalMasterAndWait() when necessary to give the control
89        * back to the master thread. When returning from this method, the slave thread MUST
90        * check for an eventual termination request (with the method isTerminationRequested()).
91        * If the termination is requested, the slave thread must perform any necessary cleanup
92        * and finish as soon as possible.
93        */
94       virtual void run()=0;
95
96     private:
97       void signalAndWait();
98
99       static void * runThread(void * instance);
100       static void threadCleanupFct(void * instance);
101
102       pthread_t _threadId;
103       ThreadStatus _threadStatus;
104       pthread_cond_t _pingPongCond;
105       pthread_mutex_t _pingPongMutex;
106
107     };
108   }
109 }
110
111 #endif