44d093d2f8
- Added build script and AMPL license file - Fixed merge errors for the makefile - Extended the makefile header - Added initial AMQ message topics - Tested remote build - Removed AMPL license file - Validated build script - Accepting the metric definition message from the EMS - Execution control status messages + solver type command line option - Executing solver component - Added instructions on use to the Solver Component source file - Explicit close of subscriptions in destrcutors if network active. - Correct handling of metric list messages and subscriptions - Adding correct message and connection properties Change-Id: If02caff12aacf8a2181c96eb6dca4a19dc23c118
175 lines
5.8 KiB
C++
175 lines
5.8 KiB
C++
/*==============================================================================
|
|
Execution control
|
|
|
|
The Solver Component should run as long as the application being optimised is
|
|
running. This requires an external message to the Solver Component about when
|
|
the Solver Component should shut down, and a way to stop other threads from
|
|
progressing until the shut down message has been processed.
|
|
|
|
The following Actor may run on its own, but it may also be included with
|
|
another Actor to avoid running a separate thread just waiting for a single shut
|
|
down message. This Actor will therefore be base class for the Solver Manager
|
|
actor, but the implementation cannot be done there since the Solver Manager is
|
|
a templated actor, and knowlege about the template parameter would be necessary
|
|
to call the function to wait for termination.
|
|
|
|
The threads calling the function to wait for termination will block until the
|
|
required message is received.
|
|
|
|
The Agent is also involved with the general component status messages to be
|
|
sent to the Solver's status topic.
|
|
|
|
Author and Copyright: Geir Horn, University of Oslo
|
|
Contact: Geir.Horn@mn.uio.no
|
|
License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
|
|
==============================================================================*/
|
|
|
|
#ifndef NEBULOUS_EXECUTION_CONTROL
|
|
#define NEBULOUS_EXECUTION_CONTROL
|
|
|
|
// Standard headers
|
|
|
|
#include <string_view> // For constant strings
|
|
#include <map> // Standard maps
|
|
#include <sstream> // Stream conversion
|
|
#include <chrono> // For standard time points
|
|
#include <condition_variable> // Execution stop management
|
|
#include <mutex> // Lock the condtion variable
|
|
|
|
// Theron++ headers
|
|
|
|
#include "Actor.hpp" // Actor base class
|
|
#include "Utility/StandardFallbackHandler.hpp" // Exception unhanded messages
|
|
|
|
// AMQ communication
|
|
|
|
#include "Communication/NetworkingActor.hpp" // The networking actor
|
|
#include "Communication/AMQ/AMQMessage.hpp"
|
|
#include "Communication/AMQ/AMQjson.hpp" // JSON messages to be sent
|
|
|
|
namespace NebulOuS
|
|
{
|
|
|
|
/*==============================================================================
|
|
|
|
Execution control
|
|
|
|
==============================================================================*/
|
|
|
|
class ExecutionControl
|
|
: virtual public Theron::Actor,
|
|
virtual public Theron::StandardFallbackHandler,
|
|
virtual public Theron::NetworkingActor<
|
|
typename Theron::AMQ::Message::PayloadType >
|
|
{
|
|
// The mechanism used for blocking other threads will be to make them wait
|
|
// for a condition variable until the message handler for the exit message
|
|
// will trigger and notifiy this variable.
|
|
|
|
private:
|
|
|
|
static bool Running;
|
|
static std::mutex TerminationLock;
|
|
static std::condition_variable ReadyToTerminate;
|
|
|
|
protected:
|
|
|
|
// There is a status message class that can be used to send the status to
|
|
// other components.
|
|
|
|
class StatusMessage
|
|
: virtual public Theron::AMQ::JSONMessage
|
|
{
|
|
public:
|
|
|
|
enum class State
|
|
{
|
|
Starting,
|
|
Started,
|
|
Stopping,
|
|
Stopped
|
|
};
|
|
|
|
private:
|
|
|
|
std::string ToString( State TheSituation )
|
|
{
|
|
static const std::map< State, std::string > StateString {
|
|
{State::Starting, "starting"}, {State::Started, "started"},
|
|
{State::Stopping, "stopping"}, {State::Stopped, "stopped"} };
|
|
|
|
return StateString.at( TheSituation );
|
|
}
|
|
|
|
std::string UTCNow( void )
|
|
{
|
|
std::ostringstream TimePoint;
|
|
TimePoint << std::chrono::system_clock::now();
|
|
return TimePoint.str();
|
|
}
|
|
|
|
public:
|
|
|
|
StatusMessage( State TheSituation,
|
|
std::string AdditionalInformation = std::string() )
|
|
: JSONMessage( std::string( StatusTopic ),
|
|
{ {"when", UTCNow() }, {"state", ToString( TheSituation ) },
|
|
{"message", AdditionalInformation } } )
|
|
{}
|
|
};
|
|
|
|
// The status of the solver is communicated on the dedicated status topic
|
|
|
|
static constexpr std::string_view StatusTopic
|
|
= "eu.nebulouscloud.solver.state";
|
|
|
|
public:
|
|
|
|
// The function used to wait for the termination message simply waits on the
|
|
// condition variable until it is signalled by the message handler. As there
|
|
// could be spurious wake-ups it is necessary to check if the actor is still
|
|
// running when the condition variable is signalled, and if so the calling
|
|
// thread will just block again in another wait.
|
|
//
|
|
// Note that returning from this function does not imply that all actors have
|
|
// closed and finished processing. One should wait for the local actor system
|
|
// to close before deleting the local actors, see the normal function
|
|
// Actor::WaitForGlobalTermination()
|
|
|
|
static void WaitForTermination( void );
|
|
|
|
// The stop message has not yet been defined and it is defined as an empty
|
|
// class here as a named placeholder for a better future definition.
|
|
|
|
class StopMessage
|
|
{
|
|
public:
|
|
|
|
StopMessage() = default;
|
|
StopMessage( const StopMessage & Other ) = default;
|
|
~StopMessage() = default;
|
|
};
|
|
|
|
protected:
|
|
|
|
// The message handler will change the value of the flag indicating that the
|
|
// Actor is running, and signalling the condition variable to indicate that
|
|
// the termination has started.
|
|
|
|
virtual void StopMessageHandler( const StopMessage & Command,
|
|
const Address Sender );
|
|
|
|
// The constructor is simply taking the name of the actor as parameter and
|
|
// initialises the base classes.
|
|
|
|
public:
|
|
|
|
ExecutionControl( const std::string & TheActorName );
|
|
|
|
ExecutionControl() = delete;
|
|
virtual ~ExecutionControl();
|
|
};
|
|
|
|
} // namespace NebulOuS
|
|
#endif // NEBULOUS_EXECUTION_CONTROL
|