Sto lavorando su un sistema di concorrenza basato su code di messaggi con un pool di thread sottostante. Una coda può indirizzare altre code. Inoltre, una coda può essere indirizzata da più code (ad es. Bambini) per creare una gerarchia ad albero e dare la priorità ad alcune code.
Voglio evitare di segnalare i thread ogni volta che un messaggio viene accodato mentre la coda (ei suoi figli) sono già stati svuotati.
Quindi la coda sa se è sleeping
o running
. La transizione da sleeping
a running
è facile. Ciò può essere fatto quando un nuovo messaggio è in coda.
Sono più preoccupato per il contrario. Come posso evitare di perdere messaggi / eventi quando eseguo la transizione da running
a sleeping
? Per chiarire: questo non è un passo atomico. Anche la coda non può andare a dormire quando i suoi figli hanno ancora bisogno di attenzione.
Al momento nella funzione sleep imposto lo stato a sleeping
, quindi controlla se la coda corrente oi suoi figli hanno eventi in sospeso che sono stati persi. Se è così, mi riattivo la coda. Ma ciò non può potenzialmente causare una ricorsione infinita di svegli - sonno - sveglio - sonno - ...?
Come posso evitarlo, o qual è il modo corretto per configurare un sistema di code di questo tipo?
In pseudo codice:
atomic state = sleeping
target = anotherQueue
children = queues that target this queue
func Async(event)
{
get lock
push event onto queue (i.e. array/fifo/...)
release lock
this.wakeup()
}
func wakeup()
{
If (state == running) { return }
state = running
!target ? drain() : target.wakeup()
}
func drain()
{
while (event = next() )
{
event.run()
}
sleep()
}
func sleep()
{
state = sleeping
*** what if an event is posted during the transition from running to sleeping? ***
//check if events have been missed
If (event.count > 0)
{
this.wakeup()
}
//check children: don't sleep if they have pending events
If (children.haveEvents) { this.wakeup }
}
func next()
{
get lock
nextEvent = pop event from queue
release lock
If (!nextEvent)
{
//check each child queue for an event
children.nextEvent
}
return nextEvent
}