我怎么醒来睡觉的pthread?

Wug*_*Wug 5 c++ linux sleep pthreads

我正在用C++编写程序.我注意到它正在获得许多线程,其目的是每隔一段时间做一些事情,其中​​有3个或4个.我决定通过编写一个调度程序服务来重构,使用这些线程的其他地方可以订阅,这应该减少我在任何时候运行的额外事件线程的数量.

我还没有任何使用它的代码; 在我开始编写它之前,我想知道它是否可行,并获得一些关于我的设计的反馈.我想要完成的内容的简要说明如下:

添加活动

  1. 来电者提供活动和时间表
  2. Schedule提供下一次事件
  3. (事件,计划)对被添加到事件队列中
  4. 中断休眠事件线程(即唤醒它)

事件线程主循环

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

我已经做了一些研究,并且知道可以中断一个休眠线程,我相信只要防止同时访问事件队列,就不应该有任何危险的行为.我想,唤醒一个线程是可能的,java的Thread的sleep()调用在某些情况下抛出一个InterruptedException,除非它不依赖于操作系统的底层睡眠调用,否则它必须以某种方式.

任何人都可以评论我的方法吗?这是一个轮子,我最好不要重新发明?具体来说,如何中断睡眠线程,以便在下一条指令处恢复执行,是否可以从被中断的线程中检测到这一点?

关于提升的说明

我敢打赌你可以编写一个带有提升的调度程序,但是这会编译并在一台机器上运行,因为缺少一个更好的短语,一堆垃圾.我之前已经编译过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
}
Run Code Online (Sandbox Code Playgroud)

这是睡眠功能:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,AddEvent:

void Scheduler::AddEvent(Event e)
{
    QueueLock();
    eventqueue.push(e);
    QueueUnlock();
    NotifyEventThread();
}
Run Code Online (Sandbox Code Playgroud)

相关变量声明:

bool threadrunning;
priority_queue<Event, vector<Event>, greater<Event> > eventqueue;
pthread_mutex_t queuelock; // QueueLock and QueueUnlock operate on this
pthread_cond_t eventclock;
Run Code Online (Sandbox Code Playgroud)

为了处理泛型事件的问题,每个事件Event包含一个指向抽象类型对象的指针action,子类重写action::DoEvent.从内部调用此方法Event::DoEvent. actions由他们的事件"拥有",即如果事件不再需要重新安排,则会自动删除它们.

Gre*_*reg 9

你要找的是pthread_cond_t对象pthread_cond_timedwaitpthread_cond_wait功能.您可以创建条件变量isThereAnyTaskToDo并在事件线程中等待它.添加新事件时,您只需唤醒事件线程即可pthread_cond_signal().

  • 小心点.您正在描述一个事件变量.条件变量有点微妙.一个事件变量表示"发生了某些事情",其中一个条件变量表示"某些东西*可能已经发生变化".条件变量只有在与互斥量配对时才能正确使用; 等待条件变量可以虚假地唤醒. (3认同)