Skip to content

Multithreading issue with creation or removal of objects #744

@MichaelSNelson

Description

@MichaelSNelson

Copy and paste from: https://forum.image.sc/t/semi-random-script-errors-when-adding-removing-objects/53617

I am using a script to demonstrate both removing and adding objects, ideally for new coders (dun dun dunnn). The setting is a small rectangular annotation with cells generated inside of it, which is also divided into tumor/stroma annotations.
image

The purpose of the script is to remove the cells in one area, run an analysis that adds measurements based only on the cells in the second area, and then restore the cells that were removed.

//Load the LuCa object data before running!
resolveHierarchy() //let's make sure all of the cells are child objects of their annotations!
tumorAnnos = getAnnotationObjects().findAll{it.getPathClass() == getPathClass("Tumor")}
tumorCells = getCellObjects().findAll{it.getParent().getPathClass() == getPathClass("Tumor")}

//Remove the tumor annotations and their cells
removeObjects(tumorAnnos,false)
removeObjects(tumorCells,false)
//Analyze->Spatial analysis->Detect centroid distances 2D

detectionCentroidDistances(true)
//Add everything back, and make sure the hierarchy is resolved!
addObjects(tumorAnnos)
addObjects(tumorCells)
resolveHierarchy()

The code works most of the time. Probably 70%? I lack my usual variety of computers to test out whether it is based on my computer - but I do have a project file hosted online I can make available to run the test.

Errors include: Null pointer exception popup in the lower right,

INFO: Starting script at Sat Jun 05 20:54:28 CDT 2021
WARN: Resolving hierarchy that contains 3 annotations and 1236 detections - this may be slow!
ERROR: QuPath exception
WARN: Resolving hierarchy that contains 3 annotations and 1236 detections - this may be slow!
INFO: Script run time: 0.25 seconds
The log file is not hugely informative on that one.

Alternatively, I sometimes see a TMA core error.

ERROR: QuPath exception: Cannot invoke "qupath.lib.objects.PathObject.isTMACore()" because "child" is null
    at qupath.lib.gui.panes.PathObjectHierarchyView$PathObjectTreeItem.getChildren(PathObjectHierarchyView.java:516)
    at qupath.lib.gui.panes.PathObjectHierarchyView$PathObjectTreeItem.isLeaf(PathObjectHierarchyView.java:544)
    at javafx.controls/javafx.scene.control.skin.TreeCellSkin.updateDisclosureNode(Unknown Source)
    at javafx.controls/javafx.scene.control.skin.TreeCellSkin.updateChildren(Unknown Source)
    at javafx.controls/javafx.scene.control.skin.LabeledSkinBase.lambda$new$5(Unknown Source)
    at javafx.controls/com.sun.javafx.scene.control.LambdaMultiplePropertyChangeListenerHandler.lambda$new$1(Unknown Source)
    at javafx.base/javafx.beans.value.WeakChangeListener.changed(Unknown Source)
    at javafx.base/com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(Unknown Source)
    at javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.markInvalid(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.set(Unknown Source)
    at javafx.graphics/javafx.css.StyleableObjectProperty.set(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectProperty.setValue(Unknown Source)
    at javafx.controls/javafx.scene.control.Labeled.setGraphic(Unknown Source)
    at qupath.lib.gui.panes.PathObjectHierarchyView$PathObjectCell.updateItem(PathObjectHierarchyView.java:423)
    at qupath.lib.gui.panes.PathObjectHierarchyView$PathObjectCell.updateItem(PathObjectHierarchyView.java:413)
    at javafx.controls/javafx.scene.control.TreeCell.updateItem(Unknown Source)
    at javafx.controls/javafx.scene.control.TreeCell.lambda$new$3(Unknown Source)
    at javafx.base/javafx.beans.WeakInvalidationListener.invalidated(Unknown Source)
    at javafx.base/com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(Unknown Source)
    at javafx.base/com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.fireValueChangedEvent(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.markInvalid(Unknown Source)
    at javafx.base/javafx.beans.property.ObjectPropertyBase.set(Unknown Source)
    at javafx.controls/javafx.scene.control.TreeView.setRoot(Unknown Source)
    at qupath.lib.gui.panes.PathObjectHierarchyView.hierarchyChanged(PathObjectHierarchyView.java:563)
    at qupath.lib.gui.panes.PathObjectHierarchyView.lambda$hierarchyChanged$11(PathObjectHierarchyView.java:559)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(Unknown Source)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)

Still other times I see another error:

ERROR: QuPath exception
    at java.base/java.util.LinkedHashMap$LinkedHashIterator.nextNode(Unknown Source)
    at java.base/java.util.LinkedHashMap$LinkedKeyIterator.next(Unknown Source)
    at qupath.lib.objects.PathObject.nDescendants(PathObject.java:475)
    at qupath.lib.objects.PathObjectTools.countDescendants(PathObjectTools.java:200)
    at qupath.lib.objects.PathObject.objectCountPostfix(PathObject.java:190)
    at qupath.lib.objects.PathObject.toString(PathObject.java:224)
    at qupath.lib.gui.panes.PathObjectListCell.updateItem(PathObjectListCell.java:66)
    at qupath.lib.gui.panes.PathObjectListCell.updateItem(PathObjectListCell.java:36)
    at javafx.controls/javafx.scene.control.ListCell.updateItem(Unknown Source)
    at javafx.controls/javafx.scene.control.ListCell.lambda$new$2(Unknown Source)
    at javafx.base/javafx.collections.WeakListChangeListener.onChanged(Unknown Source)
    at javafx.base/com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(Unknown Source)
    at javafx.base/com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(Unknown Source)
    at javafx.base/javafx.collections.ObservableListBase.fireChange(Unknown Source)
    at javafx.base/javafx.collections.ListChangeBuilder.commit(Unknown Source)
    at javafx.base/javafx.collections.ListChangeBuilder.endChange(Unknown Source)
    at javafx.base/javafx.collections.ObservableListBase.endChange(Unknown Source)
    at javafx.base/javafx.collections.ModifiableObservableListBase.setAll(Unknown Source)
    at qupath.lib.gui.panes.AnnotationPane.hierarchyChanged(AnnotationPane.java:382)
    at qupath.lib.gui.panes.AnnotationPane.lambda$hierarchyChanged$7(AnnotationPane.java:352)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(Unknown Source)
    at java.base/java.security.AccessController.doPrivileged(Unknown Source)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)

I am at a loss. The script never seems to actual fail, despite the errors. No objects end up missing, the measurements are created in the correct cells.

Sometimes it will run 7 times in a row. Sometimes it will fail 3 times in a row with the same error.
The region itself is small and shouldn’t cause any problems for my computer.
image
Just the upper left corner of the LuCa FoV image.

I have tried adding fireHierarchyUpdates() everywhere I can think or, and tried Thread.sleep(1000) along with setting the number of CPU cores to 1, as well, with no change to the behavior.

As recommended on the forum, guiscript=true is a viable workaround for the issue.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions