让线程每个周期调用init一次

Make threads call init once every cycle

本文关键字:调用 init 一次 周期 线程      更新时间:2023-10-16

我有一个代码,看起来像下面这样,有许多线程执行这个代码片段:

if (!shouldWork)
{
    long timeToSleep = 0;
    if (FindTimeToSleep(timeToSleep)) {
        Sleep(timeToSleep);
        InnerInitialize();
    }
}
}

现在,函数InnerInitialize应该只在睡眠超时后被调用一次。有许多线程可以睡眠,在他们醒来后,只有一个线程应该调用InnerInitialize。我们可以使用一个简单的信号量,但问题是,在下一个循环中,在所有线程都传递了对InnerInitialize的调用之后,如果线程再次进入睡眠状态,我们可能需要再次调用该函数(只有一次)。这类似于std::call_once,但只是周期性的。

我们如何做到这一点?

应该使用共享互斥锁进行同步。

忽略每个线程如何到达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变量,但我不完全理解它来帮助你。

当然,这是假设所有线程都在相同的时间内进入睡眠状态,并且这段时间足够长,以保证在所有其他线程醒来之前没有线程(再次)进入睡眠状态。

尝试使用单个线程来管理其余部分。你的,似乎是每个线程组,初始化和会话之间的睡眠将从一个线程管理,而组中的工作线程将在需要时做他们的东西,可能通过作业队列。

在一个"分代计数器"周围同步每个线程,这是一个简单的递增计数器,表示它的变化(通过互斥锁和条件变量)。

当计数器增加时,如果你愿意,这是一个"新的工作日",工人们知道要重新开始。一个单独的、专用的调度线程执行增量和初始化例程,它不需要知道有多少工作线程。

在伪代码:

// 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在代增量后释放的第一个线程中运行回调来进入一个工作线程。