Как разбудить спящий поток?

Пишу программу на С++. Я заметил, что он набирает несколько потоков, цель которых - делать что-то через определенные промежутки времени, их 3 или 4. Я решил провести рефакторинг, написав службу планировщика, на которую могли подписаться другие места, использующие эти потоки, что должно уменьшить количество дополнительных потоков событий, которые я запускаю в любое время, до одного.

У меня пока нет кода, использующего это; прежде чем я начну писать, я хотел бы знать, возможно ли это, и получить отзывы о моем дизайне. Краткое описание того, что я хотел бы сделать, это:

Чтобы добавить событие

  1. Звонящий предоставляет событие и расписание
  2. Расписание обеспечивает следующее появление события
  3. (пара событие, расписание )добавлена ​​в очередь событий
  4. прервать спящий поток события (, т.е.проснись)

Основной цикл потока событий

  1. попытаться получить следующее событие в очереди событий
  2. Если ожидающих событий нет, перейдите сразу к 4
  3. Получить время, когда должно произойти следующее событие
  4. Спать до следующего события (или навсегда, если нет ожидающих событий)
  5. Если сон был прерван по какой-либо причине, вернитесь к 1
  6. Если переход в спящий режим завершен успешно, выполнить текущее событие
  7. Обновить очередь (удалить событие, повторно -вставить, если это повторяющееся событие)
  8. Перейти обратно к 1

Я провел небольшое исследование и знаю, что можно прервать спящий поток, и я считаю, что до тех пор, пока одновременный доступ к очереди событий предотвращен, не должно быть никакого опасного поведения. Я полагаю, что пробуждение потока ДОЛЖНО быть возможным, вызов Java Thread sleep ()при некоторых обстоятельствах вызывает InterruptedException, и если он не полагается на базовый вызов сна операционной системы, это должно быть возможно каким-то образом.

Вопрос

Кто-нибудь может прокомментировать мой подход? Это колесо, которое мне лучше не изобретать? Как, в частности, вы можете прервать спящий поток, чтобы выполнение возобновилось со следующей инструкции, и можно ли обнаружить это в прерванном потоке?

Примечание о форсировании

Могу поспорить, что вы можете написать планировщик с boost, но он компилируется и работает на машине, которая, за неимением лучшего выражения, является кучкой дерьма. Я уже компилировал на нем программы boost, и компиляция каждого файла, который загружает boost, обычно занимает более 30 секунд. Если бы я мог избежать этого раздражающего препятствия развития, я бы очень хотел.

Приложение -Рабочий кодекс [Изменено по предложению caf]

Это код, который я создал, который работает. Он был предварительно протестирован, но правильно обрабатывал как одиночные, так и повторяющиеся события с различной задержкой.

Вот тело потока событий:

void Scheduler::RunEventLoop()
{
    QueueLock();                   // lock around queue access
    while (threadrunning)
    {
        SleepUntilNextEvent();     // wait for something to happen

        while (!eventqueue.empty() && e.Due())
        {                          // while pending due events exist
            Event e = eventqueue.top();
            eventqueue.pop();

            QueueUnlock();         // unlock
            e.DoEvent();           // perform the event
            QueueLock();           // lock around queue access

            e.Next();              // decrement repeat counter
                                   // reschedule event if necessary
            if (e.ShouldReschedule()) eventqueue.push(e);
        }
    }
    QueueUnlock();                 // unlock
    return;                        // if threadrunning is set to false, exit
}

Вот функция сна:

void Scheduler::SleepUntilNextEvent()
{
    bool empty = eventqueue.empty();  // check if empty

    if (empty)
    {
        pthread_cond_wait(&eventclock, &queuelock); // wait forever if empty
    }
    else
    {
        timespec t =                  // get absolute time of wakeup
            Bottime::GetMillisAsTimespec(eventqueue.top().Countdown() + 
                                         Bottime::GetCurrentTimeMillis());
        pthread_cond_timedwait(&eventclock, &queuelock, &t); // sleep until event
    }
}

Наконец, AddEvent:

void Scheduler::AddEvent(Event e)
{
    QueueLock();
    eventqueue.push(e);
    QueueUnlock();
    NotifyEventThread();
}

Соответствующие объявления переменных:

bool threadrunning;
priority_queue<Event, vector<Event>, greater<Event> > eventqueue;
pthread_mutex_t queuelock; // QueueLock and QueueUnlock operate on this
pthread_cond_t eventclock;

Чтобы решить проблему общих событий, каждый Eventсодержит указатель на объект абстрактного типа action, подклассы которого переопределяют action::DoEvent. этот метод вызывается изнутри Event::DoEvent. actions«принадлежат» своим событиям, т. е. они автоматически удаляются, если событие больше не нужно перепланировать.

5
задан Wug 22 August 2012 в 15:41
поделиться