我有一个类似于以下内容的代码,许多线程正在执行此代码片段:
if (!shouldWork)
{
long timeToSleep = 0;
if (FindTimeToSleep(timeToSleep)) {
Sleep(timeToSleep);
InnerInitialize();
}
}
}
现在,应该在睡眠超时后调用函数InnerInitialize一次。有许多线程可以睡眠,唤醒后,只有一个线程应该调用InnerInitialize。我们可以使用一个简单的信号量,但问题是在下一个循环中,在所有线程都已经通过对InnerInitialize的调用之后,如果线程再次进入休眠状态,我们可能需要再次调用该函数(仅一次)。所以这类似于std :: call_once,但只是定期。
我们怎样才能做到这一点?
答案 0 :(得分:2)
您应该使用共享互斥锁进行同步。
忽略每个线程如何进入Sleep(timeToSleep)
方法,这是应该发生的事情:
pthread_mutex_t mutex;
int initialized;
.......
Sleep(timeToSleep);
pthread_mutex_lock(&mutex); //critical section
if (!initialized)
{
intialized = 1;
InnerInitialize();
}
pthread_mutex_unlock (&mutex);
您仍然需要在代码中的某处重置intialized
变量,但我并不完全了解它以帮助您。
这当然假设所有线程都会在相同的时间内进入休眠状态,并且该时间段足以保证在所有其他线程都唤醒之前没有线程再次进入休眠状态。
答案 1 :(得分:1)
尝试使用管理其余部分的单个线程。你的,似乎是每个线程组,会话之间的初始化和休眠将从该一个线程进行管理,而组中的工作线程将在需要时(可能通过作业队列)完成它们的工作。
这也清楚地分离了每个线程工作的职责。
答案 2 :(得分:0)
围绕“世代计数器”同步每个线程,这只是一个递增计数器,用于指示其变化(通过互斥和条件变量)。
当计数器递增时,如果你愿意,那就是“新的工作日”,并且工人知道再次开始。一个单独的专用调度线程执行增量和初始化例程,并且不需要知道有多少工作者。
在伪代码中:
// main / global init
workCycle = new GenerationalCounter() // initialized to _generation 0
// worker thread
myCurrentCycle = 0
while true:
myCurrentCycle = workCycle.awaitNewGeneration(myCurrentCycle)
// lock mutex
// cond_wait until _generation != myCurrentCycle
// fetch _generation for return
// unlock mutex
DoWork()
// scheduler thread
while true:
SleepUntilNextWorkCycle()
InnerIntializer()
workCycle.increment() // lock mutex
// increment _generation
// broadcast
// unlock mutex
通过一点簿记,InnerInitialize()
可以通过扩展GenerationalCounter
来移出调度线程并进入其中一个工作线,以便在生成增量后释放的第一个线程中运行回调。 / p>