一尘不染

如何唤醒hibernate的pthread?

linux

我正在用C++编写程序。我注意到,它获得了许多线程,它们的目的是定期执行某项操作,其中有3或4个线程。我决定通过编写一个调度程序服务来重构,以便使用这些线程的其他地方可以预订该服务,这应该将我随时运行的额外事件线程的数量减少到一个。

我还没有使用此代码的代码。在开始编写之前,我想知道是否有可能,并获得有关我的设计的一些反馈。我要完成的任务的简要说明是这样的:

添加事件

  1. 呼叫者提供事件和时间表
  2. 时间表提供事件的下一次发生
  3. (事件,时间表)对添加到事件队列
  4. 中断睡眠事件线程(即唤醒它)

事件线程主循环

  1. 尝试获取事件队列中的下一个事件
  2. 如果没有未决事件,请直接转到4
  3. 获取应该发生下一个事件的时间
  4. 一直睡到下一个事件(如果没有等待事件,则一直hibernate)
  5. 如果睡眠由于某种原因而中断,请循环回到1
  6. 如果睡眠成功完成,则执行当前事件
  7. 更新队列(删除事件,如果是重复事件,则重新插入)
  8. 跳回1

我已经进行了一些研究,并且知道可以中断睡眠线程,并且我相信,只要防止同时访问事件队列,就不应有任何危险行为。我以为唤醒线程是有可能的,在某些情况下,java的Thread的sleep()调用会引发InterruptedException,并且除非它不依赖于操作系统的基础sleep调用,否则它一定会成为可能。

谁能评论我的方法?这是我最好不要重新发明的轮子吗?具体来说,如何中断正在hibernate的线程,以便在下一条指令处恢复执行,并有可能从被中断的线程中检测到这一点?

关于升压的注意事项

我敢打赌,您可以编写一个带有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
}

这是hibernate功能:

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由其事件“拥有”,即,如果不再需要重新安排事件,它们将被自动删除。


阅读 338

收藏
2020-06-07

共1个答案

一尘不染

您正在寻找的是pthread_cond_t对象pthread_cond_timedwaitpthread_cond_wait功能。您可以创建条件变量
isThereAnyTaskToDo 并在事件线程中等待它。添加新事件后,只需使用唤醒事件线程pthread_cond_signal()

2020-06-07