Domanda

I apprezzerebbe l'aiuto di debug comportamenti strani da un contenitore multiset. Di tanto in tanto, il contenitore sembra bloccarsi l'ordinamento. Questo è un errore frequente, evidente solo in alcune simulazioni, dopo un lungo periodo di tempo, e io sono a corto di idee. (Io sono un programmatore amatoriale - suggerimenti di tutti i tipi sono i benvenuti.)

Il mio contenitore è un std::multiset che contiene le strutture Event:

typedef std::multiset< Event, std::less< Event > > EventPQ;

con le struct Event allineati secondo loro membri double time:

struct Event {

 public:
explicit Event(double t) : time(t), eventID(), hostID(), s() {}
Event(double t, int eid, int hid, int stype) : time(t), eventID( eid ), hostID( hid ), s(stype) {}

  bool operator < ( const Event & rhs ) const {
    return ( time < rhs.time );
  }

  double time;
  ...
};

Il programma un'iterazione periodi di aggiunta eventi con tempi non ordinate per EventPQ currentEvents e tirando fuori eventi in ordine. Raramente, dopo alcuni eventi sono stati aggiunti (con perfettamente volte 'legali'), gli eventi iniziare a ricevere eseguiti fuori uso.

Che cosa potrebbe rendere gli eventi sempre non ottiene ordinato correttamente? (O che cosa potrebbe rovinare l'iteratore?) Ho controllato che tutti gli orari degli eventi aggiunti sono legittimi (cioè, tutto supera il tempo di simulazione corrente), e mi hanno anche confermato che l'errore non si verifica perché due eventi capita di avere in programma per lo stesso tempo.

mi piacerebbe suggerimenti su come lavorare attraverso questo.

Il codice per l'esecuzione e l'aggiunta di eventi è inferiore per i curiosi:

  double t = 0.0;
  double nextTimeStep = t + EPID_DELTA_T;
  EventPQ::iterator eventIter = currentEvents.begin();

while ( t < EPID_SIM_LENGTH ) {

     // Add some events to currentEvents

     while ( ( *eventIter ).time < nextTimeStep ) { 

         Event thisEvent = *eventIter;
     t = thisEvent.time;
     executeEvent( thisEvent );
     eventCtr++;
     currentEvents.erase( eventIter );
     eventIter = currentEvents.begin();

  }

  t = nextTimeStep;
  nextTimeStep += EPID_DELTA_T;
}


void Simulation::addEvent( double et, int eid, int hid, int s ) {
  assert( currentEvents.find( Event(et) ) == currentEvents.end() );

  Event thisEvent( et, eid, hid, s ); 
  currentEvents.insert( thisEvent );
}

Vorrei aggiungere che di tanto in tanto un evento, quando eseguito, eliminerà gli altri eventi da currentEvents. Questo viene fatto con

double oldRecTime = 10.0; // gets defined legitimately in simulation
EventPQ::iterator epqItr = currentEvents.find( Event(oldRecTime) );
assert( currentEvents.count( Event(oldRecTime) ) == 1 );
currentEvents.erase( epqItr );

Anche se questo codice sembra a posto, mi piacerebbe conoscere altri modi posso esaminare quello che sta succedendo -. Io attualmente utilizzando un sacco di afferma () e cout << controlli

È stato utile?

Soluzione 3

Nella simulazione, dove ho commentato

// Add some events to currentEvents

eventi venivano aggiunto al currentEvents. (Speranza che era chiaro.) Se un evento è stato aggiunto che è accaduto di appartenere alla parte superiore della coda, credo che incasinato la punta iteratore a currentEvents.begin (). I ha ripristinato l'iteratore immediatamente prima del ciclo while interno, e le cose sembrano funzionare.

I aggiornerà questa domanda se questo risulta non essere la soluzione, o se ci sono altri problemi in quello che ho qui.

Grazie a tutti coloro che hanno commentato; mi aiuta a imparare come dovrei avvicinarsi a questi problemi.

Altri suggerimenti

Il ciclo di elaborazione degli eventi non riesce a verificare se la coda è vuota. In caso contrario, tutto sembra bene (più o meno).

Ma se sei a corto di eventi in coda currentEvents, non è definito il comportamento. Si potrebbe probabilmente si manifesta come qualcosa che gli appare come evento in fase di elaborazione fuori uso.

In realtà, alcune implementazioni di contenitori associativi li ho visti rappresentato da strutture di dati "virtualmente circolari", in un senso che se si ignora la fine della sequenza controllata e continuare a iterare, il vostro iteratore emergerà all'inizio della sequenza. Potrebbe essere che qualcosa di simile sta accadendo nel vostro caso?

Un altro problema che si pone immediatamente in relazione con il codice: cosa succede se il nuovo evento arriva nella coda con il valore time che è inferiore al tempo di "corrente"? Non vedo alcun controllo che cattura questa situazione nel codice. Ovviamente, se questo accade, vale a dire se alcuni eventi arrivano "troppo tardi", potrebbero ottenere facilmente elaborati fuori uso indipendentemente da come si sceglie di implementare esso.

Se possibile, vorrei consigliare cambiare la double si sta utilizzando come chiave per un certo tipo integer invece. La chiave per una set o multiset richiede un ordinamento debole rigoroso - e double non (normalmente) soddisfano tale requisito (né qualsiasi altro tipo IEEE floating point)

.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top