Разноцветный контейнер, по-видимому, прекращает сортировку

StackOverflow https://stackoverflow.com/questions/2851868

  •  27-09-2019
  •  | 
  •  

Вопрос

Я был бы признателен за помощь в отладке некоторого странного поведения мультисметичным контейнером. Изредка контейнер, по-видимому, прекращает сортировку. Это нечастая ошибка, очевидна только в некоторых симуляциях после долгого времени, и я короче говоря на идеи. (Я любительский программист - предложения всех видов приветствуются.)

Мой контейнер - это std::multiset это держит Event Структы:

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

с Event структуры отсортированы по их 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;
  ...
};

Программа, передаваемая периодами добавления событий с неупорядоченным временем EventPQ currentEvents а затем вытягивая события в порядке. Редко, после того, как некоторые события были добавлены (с прекрасно «законным» временем), события начинают выполняться из строя.

Что может заставить события, которые когда-либо не заказываются должным образом? (Или что мог испортить итератор?) Я проверил, что все дополнительные времена события являются законным (т. Е. Все превышают текущее время моделирования), и я также подтвердил, что ошибка не возникает, потому что два события случаются, чтобы запланированы в то же время.

Я бы понравился предложения о том, как работать через это.

Код для выполнения и добавления событий ниже для любопытных:

  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 );
}

Я должен добавить, что иногда событие, когда выполняется, удалит другие события из currentEvents. Отказ Это делается с

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 );

Даже если этот код выглядит хорошо, я хотел бы узнать другие способы, которыми я могу изучить, что происходит - в настоящее время я использую много утверждений () и Cout << чеки.

Это было полезно?

Решение 3

В симуляции, где я прокомментировал

// Add some events to currentEvents

События были добавлены к текущим потокам. (Надеюсь, что было ясно.) Если было добавлено мероприятие, которое произошло, чтобы принадлежать к вершине очереди, я считаю, что он испортил итератор, указывающий на CuriesEvents. Я немедленно сбрасываю итератор перед внутренним циклом, а вещи, кажется, работают.

Я буду обновлять этот вопрос, если это оказывается не решением, или если есть и другие проблемы в том, что у меня здесь.

Благодаря всем тем, кто прокомментировал; Это помогает мне узнать, как я должен приближаться к этим проблемам.

Другие советы

Ваш цикл обработки событий не может проверить, пусто очередей. В противном случае все выглядит хорошо (более или менее).

Но если у вас закончится события в вашем currentEvents Очередь, поведение не определено. Возможно, это может проявиться как то, что появляется, когда событие обрабатывается из строя.

Фактически, некоторые реализации ассоциативных контейнеров, которые я увидел, представлял их «практически круговыми» структурами данных, в некотором смысле, что если вы игнорируете конец контролируемой последовательности и продолжаете повторять, ваш итератор появится в начале последовательности. Может ли это что-то вроде этого происходит в вашем случае?

Другой вопрос, который немедленно возникает в связи с вашим кодом: что происходит, если новое событие поступает в очередь с time Значение, которое меньше «текущего» времени? Я не вижу никаких чеков, которые будут захватывать эту ситуацию в вашем коде. Очевидно, что если это произойдет, то есть если некоторые события прибывают «слишком поздно», они могут легко обработать из строя независимо от того, как вы его реализуете.

Если вообще возможно, я бы посоветовал меняться double Вместо этого вы используете в качестве ключа к некоторому целому типу. Ключ для set или multiset требует строгого слабого упорядочения - и double делает нет (Обычно) соответствовать этому требованию (и не какая-либо другой тип плавающей точки IEEE).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top