An abstraction of a stroke represents a complete action performed by a user. This action can be canceled when it has not been finished yet, or can be undone after it’s undo data has been added to the undo stack. Every stroke consists of a set of stroke jobs. Every job sits in a queue and does a part of work that the stroke as a whole must perform on an image. A stroke job cannot be canceled while execution and you cannot undo a single job of the stroke without canceling the whole stroke.
Example: Lets look at how the Freehand Tool works. Every time the user paints a single line on a canvas it creates a stroke. This stroke consists of several stroke jobs: one job initializes indirect painting device and starts a transaction, several jobs paint dabs of a canvas and the last job merges indirect painting device into the canvas and commit the undo information.
The jobs of the stroke can demand special order of their execution. That is the way how they will be executed on a multi-core machine. Every job can be either of the type:
CONCURRENT
concurrent job may be executed in parallel with any other concurrent job of the stroke as well as with any update job executed by the scheduler
Example: in Scale Image action each job scales its own layer. All the jobs are executed in parallel.
SEQUENTIAL
if the job is sequential, no other job may interleave with this one. It means that when the scheduler encounters a sequential job, it waits until all the other stroke jobs are done, starts the sequential job and will not start any other job until this job is finished. Note that a sequential job can be executed in parallel with update jobs those merge layers and masks.
Example: All the jobs of the Freehand Tool are sequential because you cannot rearrange the painting of dabs. And more than that, you cannot mix the creation of the transaction with painting of anything on a canvas.
BARRIER
barrier jobs are special. They created to allow stroke jobs to synchronize with updates when needed. A barrier job works like a sequential one: it does not allow two stroke jobs to be executed simultaneously, but it has one significant addition. A barrier job will not start its execution until all the updates (those were requested with setDirty() calls before) has finished their execution. Such behavior is really useful for the case when you need to perform some action after the changes you requested in previous jobs are done and the projection of the image does now correspond the changes you’ve just done.
Example: in Scale Image action the signals of the image like sigSizeChanged should be emitted after all the work is done and all the updates are finished. So it runs as a barrier job. See KisProcessingApplicator class for details.
Besides one of the types above a job may be defined as EXCLUSIVE. Exclusive property makes the job to be executed on the scheduler exclusively. It means that there will be no other jobs (strokes or updates) executed in parallel to this one.
The queue of strokes
The strokes themselves are stored in a queue and executed one by one. This is important to know that any two jobs owned by different strokes cannot be executed simultaneously. That is the first job of a stroke starts its execution only after the last job of the previous stroke has finished.
The stroke is just a container for jobs. It stores some information about the work done, like id() and name(). Alongside storing this information it can affect the order of execution of jobs as well. The stroke can be defined exclusive. The meaning of this resembles the behavior of stroke job’s exclusive property. Exclusive stroke is a stroke that executes its jobs with all the updates blocked. The execution of updates will start only after the stroke is finished.
发布评论