UXOperation
UXOperation is one piece of work, together with the operations it must wait
for.
#use <UXKit> // or #import "UXOperationQueue.xc"Overview
Section titled “Overview”UXOperation* parse = UXOperation.make(2, &self.doParse);parse.addDependency(load);
void doParse(UXOperation* op) { … } // the workThe callback receives the operation itself, so one method can serve several
operations and tell them apart by tag.
UXOperationQueue runs them.
The work is a callback, so nothing is owned
Section titled “The work is a callback, so nothing is owned”callback block void(UXOperation* op)A callback never owns its receiver. An operation queued against a window does not keep that window alive, and a queue holding a hundred pending operations keeps nothing else alive.
In return, the application must keep the target alive until the work runs. An operation whose receiver has died is not an error: the callback reads as absent and the operation finishes having done nothing. That is correct for “lay out the window that just closed”, and a silent no-op if you expected the work to run.
A null block is legal and does nothing. Use one as a barrier: an operation others depend on, which exists only as a join point in the graph.
Ready means every dependency has finished
Section titled “Ready means every dependency has finished”bool isReady(void)True when nothing is outstanding, and false once the operation itself has finished, so a completed operation is never picked up twice.
Dependencies are a plain list with no cycle check at
addDependency time. A cycle shows up when the queue stops
making progress and sets
isDeadlocked. Checking
on every add would cost a graph walk per edge, and the queue has to detect the
condition anyway.
Cancel finishes without running
Section titled “Cancel finishes without running”op.cancel();op.isCancelled(); // true// after the queue runs:op.isFinished(); // ALSO true — it finished without doing the workexecute skips the block when cancelled, then marks the operation finished
regardless. Dependents proceed, so cancelling one step does not block
everything downstream.
chain 10 -> 20 -> 30, with 20 cancelled -> 10 and 30 runTwo consequences:
- Cancellation does not propagate. If a dependent must not run either, cancel it too.
- Cancelling after the operation has run has no useful effect. The state
is already finished, and
isCancelledbecomes true without anything having changed.
There is no un-cancel.
The tag is for you
Section titled “The tag is for you”i32 tagAn integer identity the toolkit never interprets.
ranTagAt reports it, so a
test uses it to assert the execution order, and one callback uses it to
distinguish the operations it serves.
Use it for a row index, an enum, a request id, or anything you can map back.
Topics
Section titled “Topics”make · addDependency · cancel · isCancelled · isFinished · isReady · execute
static UXOperation* make(i32 tag, callback block void(UXOperation* op))An operation with its tag and its work. Pass 0 for the block to make a
barrier.
addDependency
Section titled “addDependency”void addDependency(UXOperation* o)o must finish before this operation may run. A null argument is ignored
rather than stored, so a conditional dependency needs no if.
Duplicates are stored, not removed. This is harmless: readiness asks whether every entry has finished, and the same operation appearing twice gives the same answer both times. It costs one extra comparison per check.
cancel
Section titled “cancel”void cancel(void)Skips the work. See above.
isCancelled
Section titled “isCancelled”bool isCancelled(void)isFinished
Section titled “isFinished”bool isFinished(void)Whether it has been executed, including when it was cancelled.
isReady
Section titled “isReady”bool isReady(void)Whether every dependency has finished and this one has not.
execute
Section titled “execute”void execute(void)Runs the block (unless cancelled), then marks the operation finished. The queue calls this; call it directly only if you are driving the order yourself.
Fields
Section titled “Fields”i32 tagArray<UXOperation>* depsThe dependencies, held strongly. An operation keeps its prerequisites alive, since it cannot become ready without querying them.
Example
Section titled “Example”diamond, added 4,3,2,1: order: 1 3 2 4 ran=4 of 4 deadlocked=0 allFinished=1chain 10->20->30 with 20 cancelled: order: 10 30 ran=2 of 3 20 finished=1 cancelled=1three independent (9 has no block): order: 7 8 9 ran=3 of 3Tag 9 has a null block: it appears in the order because it ran, and it
produced nothing. The program is website/site/examples/uxkit/operations.xc;
the doc-examples gate compiles it, and this is its output.
Conforms to
Section titled “Conforms to”- A plain class (not an
Objectsubclass)
See also
Section titled “See also”UXOperationQueue: what runs these- Bound methods and callbacks: why a dead target is a silent skip