How do I wake up to sleep?

I am writing a program in C ++. I noticed that he receives several streams, the purpose of which is to do something at intervals, there are 3 or 4. I decided to reorganize by writing a scheduler service into which other places that use these streams can subscribe, which should reduce the number of additional streams events that I started at any time, just one.

I don't have code that hasn't used it yet; before I start writing, I would like to know, if possible, and get some feedback on my design. A brief description of what I would like to do is the following:

To add an event

  • Caller provides event and schedule
  • The schedule provides the next occurrence of the event. A few words
  • (event, schedule) is added to the event queue
  • interrupt a sleeping stream of events (i.e. wake it up)

The main event flow loop

  • try to get the next event in the event queue
  • If there is no pending event, go straight to 4
  • Get the time during which the next event should occur.
  • Sleep until the next event (or forever if there is no pending event)
  • If the dream was interrupted for any reason, go back to 1
  • If the dream is successful, execute the current event.
  • Refresh queue (delete event, reinsert if it is a recurring event)
  • Go to 1

, , , , . , , java Thread sleep() , , , - .

- ? , ? , , , , ?

, boost, , , - , . , , , 30 . , .

- [ ]

, , . , , .

:

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, whos action::DoEvent. Event::DoEvent. actions "" , , .

+5
4

, , pthread_cond_t, pthread_cond_timedwait pthread_cond_wait. isThereAnyTaskToDo . , pthread_cond_signal().

+9

* NIX, Windows. , - / . POSIX pthread_cond_timedwait(). Windows WaitForSingleObject() , CreateTimerQueueTimer() CreateWaitableTimer(). Boost , , POSIX, .

UPDATE:

POSIX , . create_timer()

+3

wilx - pthread_cond_timedwait() , . , :

  • , 4
  • , .
  • condition pthread_cond_timedwait() ( pthread_cond_wait(), )
  • , 4
  • ( , , )
  • 5

, , - , , , , . , , , , - .

, , --expire .

+3

- , :

QueueLock();                      // lock around queue access
bool empty = eventqueue.empty();  // check if empty
QueueUnlock();                    // unlock

pthread_mutex_lock(&eventmutex);  // lock event mutex (for condition)
if (empty)
{
    pthread_cond_wait(&eventclock, &eventmutex); // wait forever if empty
}

, , , QueueUnlock() pthread_mutex_lock(&eventmutex) - . , SleepUntilNextEvent() eventqueue.top(), .

, pthread_cond_wait(), , , . " " - , , , :

void Scheduler::RunEventLoop()
{

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

            pthread_mutex_unlock(&queuemutex);
            e.DoEvent();           // perform the event
            e.Next();              // decrement repeat counter
            pthread_mutex_lock(&queuemutex);
                                   // reschedule event if necessary
            if (e.ShouldReschedule()) eventqueue.push(e);
        }

        SleepUntilNextEvent();     // wait for something to happen
    }
    pthread_mutex_unlock(&queuemutex);

    return;                        // if threadrunning is set to false, exit
}

/* Note: Called with queuemutex held */
void Scheduler::SleepUntilNextEvent()
{
    if (eventqueue.empty())
    {
        pthread_cond_wait(&eventclock, &queuemutex); // wait forever if empty
    }
    else
    {
        timespec t =                  // get absolute time of wakeup
            Bottime::GetMillisAsTimespec(eventqueue.top().Countdown() + 
                                         Bottime::GetCurrentTimeMillis());
        pthread_cond_timedwait(&eventclock, &queuemutex, &t); // sleep until event
    }
}

Note that pthread_cond_wait()and pthread_cond_timedwait()release the mutex during the waiting time (the mutex is released and begins waiting atomically with respect to mutex signal), so the scheduler does not hold the mutex at bedtime.

+1
source

All Articles