Login  Register

Re: ExtendedPlugInFilter, GenericDialog and synchronization

Posted by Michael Schmid on Jun 28, 2015; 10:13am
URL: http://imagej.273.s1.nabble.com/ExtendedPlugInFilter-GenericDialog-and-synchronization-tp5013333p5013337.html

Hi Adrian,

the parameters from the showDialog method (GenericDialog) are usually
passed via class variables (=global variables). So they can change any
time during preview time, while run(ip) is active. In addition, if
parameters are changed, the thread executing run(ip) will get an
interrupted condition, and after finishing (either because it checks for
being interrupted and then exits or after finishing), run(ip) will be
started again in the same thread (the previewing thread).

If the run(ip) method can have a problem with its parameters being changed
asynchronously (other than producing unusable output), in run(ip) you can
call a method with passing all parameters. Such a method, when declared
public, might be also nice for people who want to use the plugin directly
on an ImageProcessor:

public class ... implements ExtendedPlugInFilter, DialogListener {
    double paramN;   //filter parameters = dialog parameters
    boolean praremB;


    public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
        paramN = gd.getNextNumber();
        paramB = gd.getNextBoolean();
        ...
    }

    public void run(ImageProcessor ip) {
        doFiltering(ip, paramN, paramB);
    }

    public static void doFiltering(ImageProcessor ip, double paramN,
boolean paramB) {
         // here the filtering is really done.
         ...
    }
}

The doFiltering method can be static if you don't access any class
variables. E.g. if you want to display a progress bar and you process
stacks or RGB images with the CONVERT_TO_FLOAT flag, you need to know the
number of passes, so it can't be static any more.

After preview, there is no danger of a asynchronous modification of
parameters any more.

---

PARALLELIZE_IMAGES for processing an image with several threads: This
happens already during preview, so you can have asynchronous modification
of parameters also while only one image part is processed. This does not
cause an additional problem if you use the 'doFiltering' approach above;
each thread will get a different ROI with a different range of y
coordinates.

There is another point unrelated to preview: With PARALLELIZE_IMAGES, you
have to be aware that other threads may modify other parts of the image.
If your code needs to read pixels from a row different from the one it
writes to (i.e., if the neighborhood of a pixel affects the result), use
the snapshot to get the original data (SNAPSHOT flag).

---

There can be an asynchronous modification of nPasses: If you process a
stack and specify KEEP_PREVIEW and PARALLELIZE_STACKS, the preview thread
may still work on the currently visible stack slice while the user presses
<OK> and ImageJ calls setNPasses with the number of stack slices to
process the stack (it will omit the slice already handled by the preview
thread).

So the code should not use setNPasses for anything critical.
setNPasses is meant for showing a progress bar. It won't hurt if the
progress bar is inaccurate in a few cases. Typical code looks like the
following:

    double progressDone = 0.0;
    int nPasses;


    public void setNPasses (int nPasses) {
        this.nPasses = nPasses;
        progressDone = 0.0;
    }

    public void doFiltering(...) {
        for (y=0; y<height; y++) {
            progressDone += 1.0/(height*nPasses); //not thread safe, but
don't care
            if (y%10==0) { //from time to time, update the progress bar...
                IJ.showProgress(progressDone);
                // ...and check whether preview got interrupted:
                if (Thread.currentThread().isInterrupted()) return;
            }
            ...
        }
    }

So in general, no real precautions are necessary for multithreading in
ExtendedPlugInfilters, with very few exceptions:
- Use a separate doFiltering method with a local set of parameters if
processing could crash in case of asynchronous modification of parameters.
- Do not use setNPasses for anything critical.
- As usual in multithreaded programming, in code that may run
asynchronously, don't modify class variables unless you understand what
you are doing. In practice, it makes sense to start coding with a static
doFiltering method, where the compiler checks that you don't accidentally
use class variables. Get all coding and testing done like this. At the end
make it non-static to add the progress bar.

---

ImageJ2: I am not familiar with the current status; it's pretty long ago
that I had a look into this and at that time preview was not supported by
the ImageJ2 way of defining plugins. Others will be more knowledgeable.


Michael
______________________________________________________________


On Sat, June 27, 2015 17:28, Adrian Daerr wrote:

> Hello,
>
> I want to write an ExtendedPlugInFilter with a preview checkbox. For
> preview, the API documentation of that interface at
>   http://imagej.nih.gov/ij/developer/api/
> says that "a separate thread may call setNPasses(nPasses) and run(ip)
> while the dialog is displayed". It does not say anything about
> synchronization: is this something I need to worry about ?
>
> More specifically, how does the preview thread get its parameters in
> run(ip) ? If the GenericDialog is queried from the preview thread, do
> I have a guarantee that the values are the same as those seen by the
> dialog handling thread ? Otherwise, what is the recommended way of
> synchronizing ?
>
> A similar issue arises when plugin returns the PARALLELIZE_IMAGES /
> PARALLELIZE_STACKS flags, although one may argue that the dialog has
> probably been quit by the time the processing takes places (but the
> processing threads might stem from a worker pool created before the
> dialog, and have a different view of the memory than the gui threadq
> ?). Is it up to the plugin author to properly synchronize stuff ? How
> is this best done ?
>
> Multithreaded programming always gives me a headache, and as there is
> no mention of thread-safety in the docs I figured I'd ask.
>
> Is the situation clearer with ImageJ2 ?
>
> cheers,
> Adrian
>
> --
> ImageJ mailing list: http://imagej.nih.gov/ij/list.html
>

--
ImageJ mailing list: http://imagej.nih.gov/ij/list.html