Конечно :) Просто удерживайте внутреннюю очередь заданий и перечисляйте их, когда процессор заданий находится в режиме запуска. В любом другом режиме просто ставьте новые задания в очередь, пока процессор не перейдет в режим запуска.
type 'a msg = // '
| Start
| Stop
| Pause
| Job of (unit -> unit)
type processQueue() =
let mb = MailboxProcessor.Start(fun inbox ->
let rec loop state (jobs : System.Collections.Generic.Queue<_>) =
async {
if state = Start then
while jobs.Count > 0 do
let f = jobs.Dequeue()
f()
let! msg = inbox.Receive()
match msg with
| Start -> return! loop Start jobs
| Pause -> return! loop Pause jobs
| Job(f) -> jobs.Enqueue(f); return! loop state jobs
| Stop -> return ()
}
loop Start (new System.Collections.Generic.Queue<_>()))
member this.Resume() = mb.Post(Start)
member this.Stop() = mb.Post(Stop)
member this.Pause() = mb.Post(Pause)
member this.QueueJob(f) = mb.Post(Job f)
Этот класс ведет себя как ожидалось: вы можете ставить задания в очередь в состоянии «Пауза», но они будут выполняться только в состоянии «Старт». После того, как processQueue остановлен, он не может быть перезапущен, и ни одно из заданий в очереди не будет запущено (достаточно просто изменить это поведение, чтобы вместо уничтожения очереди оно просто не ставило задание в состояние Stop ).
Используйте MailboxProcessor.PostAndReply , если вам нужна двусторонняя связь между процессором почтового ящика и вашим кодом.