Since the main thread and the network thread cannot communicate directly to ensure thread safety, helper classes have been created to aid in the communcation with the network thread.
As referenced in How the Visuals and The Network Work Together the agents are the way the network communicates with the main thread and event signalers are the way that the main thread communicates with the network thread.
Shared Network Signaler
The makVrf::DtSharedNetworkSignaler is the main class used in order to send event signals to the network thread. This class is one of the lowest levels in the main thread to communicate with the network thread. This class will be used by other higher level classes which wrap it to do network thread communication.
The Remote Controller
The makVrf::DtGuiThreadVrfRemoteController class mirrors the DtVrfRemoteController class which is used to communicate with the back-end over the exercise connection. The remote controller class has a similar API that uses the shared network signaler to send messages to the network thread that will ultimately use the DtVrfRemoteController to communicate with the network. One of the more convenient ways to communicate to the network thread is via vrforces interface messages. The interface messages are protocol independent such that you can create a message in the front-end and send it to the back-end using the remote controller class
This message is processed on the network side and is used to call the network protocol remote controller
The Network Callback Manager
The makVrf::DtGuiThreadNetworkCallbackManager is the main threads interface to receipt of network messages (see Network Message Agent). These interface messages can be used in the main thread to process simulation information in a protocol independent way. This concept is used throughout the front-end, and, is used to connect to specific messages that want to be received by a particular class. There are some convenience macros defined that you can use to connect (or disconnect) for these messages:
#define CONNECT_FOR_SIM_MESSAGE(_type, _function) makVrf::DtGuiThreadNetworkCallbackManager::instance(myDe).simMessageSignal(_type).connect(_function);
#define DISCONNECT_FOR_SIM_MESSAGE(_type, _function) makVrf::DtGuiThreadNetworkCallbackManager::instance(myDe).simMessageSignal(_type).disconnect(_function);
#define CONNECT_FOR_OBJECT_MESSAGE(_type, _function) makVrf::DtGuiThreadNetworkCallbackManager::instance(myDe).objectMessageSignal(_type).connect(_function);
#define DISCONNECT_FOR_OBJECT_MESSAGE(_type, _function) makVrf::DtGuiThreadNetworkCallbackManager::instance(myDe).objectMessageSignal(_type).disconnect(_function);
#define CONNECT_FOR_COMMENT_INTERACTION(_function) makVrf::DtGuiThreadNetworkCallbackManager::instance(myDe).networkInterfaceMessageSignal(DtCommentInteractionInterface::theName()).connect(_function);
#define DISCONNECT_FOR_COMMENT_INTERACTION(_function) makVrf::DtGuiThreadNetworkCallbackManager::instance(myDe).networkInterfaceMessageSignal(DtCommentInteractionInterface::theName()).disconnect(_function);
#define CONNECT_FOR_INFLUENCE_INTERACTION(_function) makVrf::DtGuiThreadNetworkCallbackManager::instance(myDe).networkInterfaceMessageSignal(DtInfluenceInteractionInterface::theName()).connect(_function);
#define DISCONNECT_FOR_INFLUENCE_INTERACTION(_function) makVrf::DtGuiThreadNetworkCallbackManager::instance(myDe).networkInterfaceMessageSignal(DtInfluenceInteractionInterface::theName()).disconnect(_function);
#define CONNECT_FOR_RADIO_MESSAGE(_type, _function) makVrf::DtGuiThreadNetworkCallbackManager::instance(myDe).radioMessageSignal(_type).connect(_function);
#define DISCONNECT_FOR_RADIO_MESSAGE(_type, _function) makVrf::DtGuiThreadNetworkCallbackManager::instance(myDe).radioMessageSignal(_type).disconnect(_function);
When connecting to a callback, it is also important (when no longer needed or in an object destructor) to disconnect from this callback to prevent unexecpected message receipt or crashes if the system tries to make a callback to a deleted object. As you an see, there are different types of messages that can be received by the front-end, so, when making your connection, it is important to know which kind of message you are expecting to receive:
-
CONNECT_FOR_SIM_MESSAGE - This connection is made to receive interface content messages from the back-end. Interface content messages are generalized messages that are typically sent to the back-end as a whole. They can be processed by inidividual objects, however, they will be passed to each object to see if that object wants to respond to the message
myIntersectionRequestId = DtGuiThreadVrfRemoteController::instance(myDe).generateRequestId();
boost::bind(&DtLastPointClickedWidgetLogic::processIntersectionResponse,
this, _1));
boost::bind(&DtLastPointClickedWidgetLogic::processIntersectionResponse,
this, _1));
DtGuiThreadVrfRemoteController::instance(myDe).sendMessage(msg, DtVrfSimBackendManager::instance(myDe).preferredBackendAddress());
void DtLastPointClickedWidgetLogic::processIntersectionResponse(
DtSimMessage* msg)
{
if (!myRequestSoilTypeInformation)
{
return;
}
-
CONNECT_FOR_OBJECT_MESSAGE - This callback will be triggered on receipt of a DtAdminMessage. The admin messages are sent to a specific entity, and, that entity will then respond with the information requested
DtRadarModeRequestor::DtRadarModeRequestor(DtDe& de)
: DtEmitterModesRequestor(de)
{
boost::bind(&DtRadarModeRequestor::processRadarModes,
this, _1));
}
void DtRadarModeRequestor::requestModes(
const DtUUID& entityName)
{
if (myEntitiesTable.find(entityName) == myEntitiesTable.end())
{
DtGuiThreadVrfRemoteController::instance(myDe).sendMessageToObject(adminMsg);
}
}
-
CONNECT_FOR_COMMENT_INTERACTION - This callback will be triggered on receipt of DIS DtCommentInteraction. The comment interaction will be translated from a protocol specific interaction to a protocol independent data structure.
boost::bind(&DtObjectConsoleMessageHandler::processObjectConsoleMessageCallback,
this, _1));
boost::bind(&DtObjectConsoleMessageHandler::processObjectConsoleMessageCallback,
this, _1));
void DtObjectConsoleMessageHandler::processObjectConsoleMessageCallback(DtNetworkMessageInterface* i)
{
DtCommentInteractionInterface* comment = dynamic_cast<DtCommentInteractionInterface*>(i);
if (!comment)
{
return;
}
See Network Callback Manager (networkCallbackManager) and How the Visuals and The Network Work Together
-
CONNECT_FOR_INFLUENCE_INTERACTION - Relevant for HLA protocol only, this callback will be triggered when an influence interaction is received
boost::bind(&DtInfluenceManager::processInfluenceMessageCallback,
this, _1));
void DtInfluenceManager::processInfluenceMessageCallback(DtNetworkMessageInterface* i)
{
DtInfluenceInteractionInterface* influence = dynamic_cast<DtInfluenceInteractionInterface*>(i);
if (!influence)
{
return;
}
if(influence->isOfClass("ProvidingSupplies"))
{
if (influence->stop())
{
removeSupplyLine(influence);
}
else
{
if (influence->duration() >= 0)
{
influence->setDuration(std::max(influence->duration(), myMinimumInfluenceDuration));
}
createSupplyLine(influence);
}
}
else if(influence->isOfClass(DtInfluenceInteractionInterface::theEngagementInfluenceName))
{
if(influence->isOfClass(DtInfluenceInteractionInterface::theIndirectFireInfluenceName))
{
std::string inflType("IF-");
inflType += influence->influenceType();
influence->setInfluenceType(inflType);
}
if (influence->stop())
{
removeAttackLine(influence);
}
else
{
if (influence->duration() >= 0)
{
influence->setDuration(std::max(influence->duration(), myMinimumInfluenceDuration));
}
createAttackLine(influence);
}
}
}
-
CONNECT_FOR_RADIO_MESSAGE - Radio message types represent messages that are sent over the network as signal interactions as VRF radio messages. This callback will be triggered when a radio messages is received.
boost::bind(&DtVrfSpotReportManager::processReceiveSpotReport,
this, _1));
boost::bind(&DtVrfSpotReportManager::processReceiveSpotReports,
this, _1));
{
{
{
std::vector<DtSimReport*> reports = spotReps->
reports();
std::set<unsigned long> resendIds;
std::vector<DtSimReport*>::const_iterator iter = reports.begin();
while (iter != reports.end())
{
if (spotRep)
{
addOrUpdateSpotReport(DtVrfSpotReportDataHandler::handlerType(), spotRep, spotRep->
contact());
}
++iter;
}
std::set<unsigned long>::const_iterator resendIter = resendIds.begin();
while (resendIter != resendIds.end())
{
mySpotReportRequestIds.erase(*resendIter);
++resendIter;
}
}
}
}
The most common kind of message send is the interface content message.
- Attention
- Note that the memory that is passed in will be deleted when all the calls have processed this message. If you wish to hold onto the message make a clone() of it.