简体   繁体   English

条件变量虚假唤醒/循环任务

[英]Condition variable spurious wakeup/round robin tasks

I'm new to C++ threading and I'm trying to write a round robin (cooperative) task manager using C++ threads. 我是C ++线程的新手,我正在尝试使用C ++线程编写循环(合作)任务管理器。 Is the declaration of round_robin_task_ulock below valid - it's a global static variable. 下面的round_robin_task_ulock声明是否有效-这是一个全局静态变量。 I want to defer locking the mutex until the task manager thread starts running. 我想将互斥锁的锁定推迟到任务管理器线程开始运行之前。

static std::mutex                      round_robin_task_mutex;
static std::condition_variable         task_manager_cvar; 
static thread                          round_robin_task_manager_thread;
static std::unique_lock<std::mutex>    
     round_robin_task_ulock(round_robin_task_mutex, std::defer_lock);

static void round_robin_task_manager()
{
    round_robin_task_ulock.lock();
    //..
}

Once the task manager thread is running it can start a round robin task running with a notify followed by wait 任务管理器线程一旦运行,就可以启动循环任务,并在运行通知的同时等待

 round_robin_tasks[current_task_id].task_cvar.notify_one();
 // release the mutex and go to sleep
 task_manager_cvar.wait(round_robin_task_ulock); 
 // now we own the mutex again

and when a round robin task wants to suspend itself it notifies the task manager thread 当循环任务想要暂停自身时,它会通知任务管理器线程

 task_manager_cvar.notify_one();
 round_robin_tasks[current_task_id].task_cvar.wait
                  (round_robin_task_ulock, [] { return  
                      round_robin_tasks[my_task_id].task_running_now; } );

Are there any obvious problems with this? 这有什么明显的问题吗? I've read about spurious wake. 我读过有关虚假唤醒的信息。 Is it possible that a spurious wake could wake up the task manager thread while a round robin task still owned the mutex or is it guaranteed that when the wait function returns, the mutex is always owned (locked) by the thread that called wait. 在循环任务仍拥有互斥锁的情况下,是否有可能通过虚假唤醒唤醒任务管理器线程,还是可以保证当wait函数返回时,互斥锁始终由调用wait的线程拥有(锁定)。

You should build your code so that without any condition variable it would still work. 您应该构建代码,以便在没有任何条件变量的情况下仍然可以正常工作。 If it would work if it locked a mutex, checked for the condition, unlocked the mutex and immediately repeated the loop, then it will work with a condition variable, only more efficiently. 如果它在锁定互斥锁,检查条件,解锁互斥锁并立即重复循环的情况下能够工作,则它将与条件变量一起使用,效率只会更高。

An implementation could wake your condition variables every 10 milliseconds, if it wanted to for some reason, or if there was some weird interaction with instructions like MWAIT, cache lines and Transactional Locks or some other strange hardware feature. 如果某个实现由于某种原因想要执行此操作,或者与诸如MWAIT,高速缓存行和事务锁之类的指令进行某种怪异的交互,则该实现可以每10毫秒唤醒一次条件变量。

I seem to recall reading about an architecture that would signal wait events on memory locations whenever any part of that cache line was written. 我似乎回想起曾经读过的一种架构,该架构会在每次写入高速缓存行的任何部分时发出信号通知存储单元中的等待事件。 And the thread library didn't pad the structure enough for the cache line size. 而且线程库没有为缓存行大小填充足够的结构。

So YES you might have to handle hundreds of wakes per second and your code should still work correctly. 因此, 是的,您可能必须每秒处理数百次唤醒,并且您的代码仍应正常工作。

From what I see of what you've written, you have only one place that you are checking the predicate , which is the condition that must be true to proceed past the condition. 从我所写的内容来看,检查谓词的位置只有一个,这是经过条件必须为真的条件。 And before every notify you should have updated the predicate. 并且在每次通知之前,您都应该更新谓词。 The predicate must always be written or read while protected by the same lock used by the condition variable. 谓词必须始终被条件变量使用的同一锁保护时进行写入或读取。

If you want different behavior you might rather use a semaphore . 如果您想要不同的行为,您可能宁愿使用信号量

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM