8.18
top
← prev up next →

process-queueπŸ”— i

Lukas Lazarek <lukas dot lazarek at eecs dot northwestern dot edu>

This library implements a queue to manage the execution of many OS level processes in parallel.

Processes are described by a function that launches something and returns information about the launched thing. Specifically, the function returns process-info , which packages together
  • a function to control the process as it runs, in the style of process ,

  • a process will, and

  • data to associate with the process

The process will describes what to do with a process when it terminates. For instance, the will might collect the results of the process, perform cleanup, and even enqueue a new process to "follow up" on the one that just terminated. In detail, the will is a function accepting the current state of the process queue and the process’s process-info and producing an updated process queue.

The process queue keeps track of the processes actively running and those waiting to run. The operations on the process queue add processes to the waiting list, manage process termination and will execution, and wait for all processes to terminate.

For convenience, the process queue also has a field for storing client data. This is useful for storing information related to processes on the side, since the queue is accessible to process wills.

This library provides several implementations of this basic concept which all conform to the same Process queue interface. First, Functional process queues implements the basic process queue in a functional style (such that the process queue is immutable). Second, Functional process priority queue implements a priority-queue version in a functional style. Third, Imperative process queues implements an imperative version of the basic process queue. Finally, Imperative process priority queue implements a priority-queue version in an imperative style.

1Example usageπŸ”— i

This is an illustrative example of the usage of the Imperative process queues implementation.

It creates a queue that runs up to two processes simultaneously, and then enqueues three processes to be run (1, 2, and 4).

The first two are launched immediately. The second process terminates quickly, and its process will enqueues a followup process (3).

Process 4 is then launched, and after it terminates process 3 is launched and terminates.

Finally process 1, which had been running since the start, terminates.

Examples:
> (require process-queue)
> (define (simple-processcmdwill)
(match-define (list stdoutstdinpidstderrctl)(process cmd))
(process-info stdout
ctl
will))
> (define (will:show-result/close-portsqinfo)
(define stdout(process-info-data info))
q)
> (begin
(λ ()
(displayln "launch 1")
(simple-process"sleep 5; echo done 1"
will:show-result/close-ports)))
(λ ()
(displayln "launch 2")
(simple-process"sleep 1; echo done 2"
(λ (qinfo)
(will:show-result/close-portsqinfo)
q
(λ ()
(displayln "launch 3")
(simple-process"echo done 3"
will:show-result/close-ports)))))))
(λ ()
(displayln "launch 4")
(simple-process"echo done 4"
will:show-result/close-ports)))

launch 1

launch 2

done 2

launch 4

done 4

launch 3

done 3

done 1

2Process queue interfaceπŸ”— i

All of the implementations below provide the following operations on process queues.

procedure

( process-queue? q)boolean?

q:any/c
The predicate recognizing process queues.

A process queue is empty if it has no actively running processes and no waiting processes.

procedure

( process-queue-enqueue qlaunch[extra-data])process-queue?

launch:(-> process-info/c )
extra-data:any/c =#f
Enqueues a process on the queue. launch should launch the process (e.g. with process , but not necessarily) and return its process-info .

extra-data provides optional extra information that may or may not be used depending on the implementation (for example, a priority value).

Returns the updated process queue.

Blocks waiting for all of the processes in the queue to terminate, handling the process wills of processes as they terminate.

Returns the number of actively running processes at the time of call.

Returns the number of waiting processes at the time of call.

Sets the value of the queue’s data field.
Gets the value of the queue’s data field.

struct

(struct process-info (datactlwill))

data:any/c
ctl:((or/c 'status'wait'interrupt'kill). -> .any )
The struct packaging together information about a running process.
=
((or/c 'status'wait'interrupt'kill). -> .any )
The contract for process-info s.
The contract for process wills.

3Imperative process queuesπŸ”— i

These imperative process queue implementations mutate a single process queue in-place. Hence, all of the Process queue interface operations that return a new process queue simply return the input queue after mutating it. (The interface returns the queue to support the Functional process queues.)

3.1Plain imperative process queueπŸ”— i

procedure

( make-process-queue active-limit
[ data
#:kill-older-thanprocess-timeout-seconds])
active-limit:positive-integer?
data:any/c =#f
process-timeout-seconds:(or/c positive-real?#f)=#f
Creates an empty imperative process queue.

active-limit is the maximum number of processes that can be active at once.

data initializes the data field of the queue which can be accessed with process-queue-get-data and process-queue-set-data .

process-timeout-seconds, if non-false, specifies a "best effort" limit on the real running time of each process in seconds. Best effort here means that the timeout is not strictly enforced in terms of timing — i.e. a process may run for longer than process-timeout-seconds. Instead, the library checks for over-running processes periodically while performing other operations on the queue and kills any that it finds. This is useful as a crude way to ensure that no process runs forever. If you need precise/strict timeout enforcement, you might consider using the timeout unix utility or other racket tools, and using process-timeout-seconds as a fallback.

3.2Imperative process priority queueπŸ”— i

package: process-queue

Imperative process priority queues prioritize processes to run first using a sorting function, provided when creating the queue. These queues use the third argument of process-queue-enqueue as the priority, which defaults to 0 if not provided.

procedure

( make-process-queue active-limit
[ data
priority>
#:kill-older-thanprocess-timeout-seconds])
active-limit:positive-integer?
data:any/c =#f
priority>:(any/c any/c . -> .boolean? )=>
process-timeout-seconds:(or/c positive-real?#f)=#f
Creates an empty imperative process priority queue, which prioritizes processes according to priority>.

See Plain imperative process queue for more details on the remaining arguments.

4Functional process queuesπŸ”— i

These implementations mirror the imperative versions, but all queue operations functionally transform the queue instead of mutating it in-place.

That means that you (the user of this library) must thread the queue around your program and take care never to use a stale queue: only the latest queue is valid, because queue values reflect the state of external and stateful processes. Hence, the functional implementations are a little strange, and you’re probably better off using the Imperative process queues. That said, sometimes a functional interface fits better with the rest of one’s program structure, caveats and all.

4.1Plain functional process queueπŸ”— i

procedure

( make-process-queue active-limit
[ data
#:kill-older-thanprocess-timeout-seconds])
active-limit:positive-integer?
data:any/c =#f
process-timeout-seconds:(or/c positive-real?#f)=#f
Creates an empty functional process queue.

See Plain imperative process queue for more details on the remaining arguments.

4.2Functional process priority queueπŸ”— i

Functional process priority queues prioritize processes to run first using a sorting function, provided when creating the queue. These queues use the third argument of process-queue-enqueue as the priority, which defaults to 0 if not provided.

procedure

( make-process-queue active-limit
[ data
priority>
#:kill-older-thanprocess-timeout-seconds])
active-limit:positive-integer?
data:any/c =#f
priority>:(any/c any/c . -> .boolean? )=>
process-timeout-seconds:(or/c positive-real?#f)=#f
Creates an empty functional process priority queue, which prioritizes processes according to priority>.

See Plain imperative process queue for more details on the remaining arguments.

top
← prev up next →

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /