Skip to content
Snippets Groups Projects
Commit c5cfbdc6 authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Efficient concurrent thread-safe implementation of HausdorffDistMeshVisitor

parent 33d3d853
No related branches found
No related tags found
No related merge requests found
......@@ -8,14 +8,25 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Visitor for Hausdorff distance.
* This visitor is instantiated on a single mesh facet or multiple facets.
* When applied to other facets, it computes Huasdorff distance to them.
* <p>
* This visitor is thread-safe. A single instance of the visitor can be used
* to inspect multiple mesh models or facets simultaneously.
* </p>
*
* @author Matej Lukes
* @author Radek Oslejsek
......@@ -23,7 +34,7 @@ import java.util.Set;
public class HausdorffDistMeshVisitor extends MeshVisitor {
private boolean relativeDistance;
private Map<MeshFacet, List<Double>> distances = new HashMap<>();
private final Map<MeshFacet, List<Double>> distances = new HashMap<>();
/**
* @param mainFacets Facets of which distance to other facets is computed. Must not be {@code null}
......@@ -31,7 +42,7 @@ public class HausdorffDistMeshVisitor extends MeshVisitor {
* to the normal vectors of source facets (normal vectors have to present),
* i.e., we can get negative distances.
* @param concurrently If {@code true} and this visitor is thread-safe, then
* the visitor is applied concurrently on multiple mesf facets.
* the visitor is applied concurrently when inspecting multiple mesh facets.
* @throws IllegalArgumentException if some parametr is wrong
*/
public HausdorffDistMeshVisitor(Set<MeshFacet> mainFacets, boolean relativeDistance, boolean concurrently) {
......@@ -51,7 +62,7 @@ public class HausdorffDistMeshVisitor extends MeshVisitor {
* to the normal vectors of source facets (normal vectors have to present),
* i.e., we can get negative distances.
* @param concurrently If {@code true} and this visitor is thread-safe, then
* the visitor is applied concurrently on multiple mesf facets.
* the visitor is applied concurrently when inspecting multiple mesh facets.
* @throws IllegalArgumentException if some parametr is wrong
*/
public HausdorffDistMeshVisitor(MeshFacet mainFacet, boolean relativeDistance, boolean concurrently) {
......@@ -68,7 +79,7 @@ public class HausdorffDistMeshVisitor extends MeshVisitor {
* to the normal vectors of source facets (normal vectors have to present),
* i.e., we can get negative distances.
* @param concurrently If {@code true} and this visitor is thread-safe, then
* the visitor is applied concurrently on multiple mesf facets.
* the visitor is applied concurrently when inspecting multiple mesh facets.
* @throws IllegalArgumentException if some parametr is wrong
*/
public HausdorffDistMeshVisitor(MeshModel mainModel, boolean relativeDistance, boolean concurrently) {
......@@ -80,18 +91,65 @@ public class HausdorffDistMeshVisitor extends MeshVisitor {
@Override
protected void visitMeshFacet(MeshFacet comparedFacet) {
int threads = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool(threads);
List<Future<MeshVisitor>> results = new LinkedList<>();
for (Map.Entry<MeshFacet, List<Double>> entry: distances.entrySet()) {
List<MeshPoint> vertices = entry.getKey().getVertices();
List<Double> distList = entry.getValue();
boolean firstComparison = distList.isEmpty();
if (concurrently()) {
for (int i = 0; i < vertices.size(); i++) {
Point2MeshVisitor visitor = new Point2MeshVisitor(vertices.get(i), relativeDistance, true);
comparedFacet.accept(visitor);
Future<MeshVisitor> result = executor.submit(visitor); // fork and continue
results.add(result);
}
updateFacetDistancesConcurrently(distList, results);
} else {
updateFacetDistancesSequentially(vertices, distList, comparedFacet);
}
}
}
/**
* Sequentially updates distances of particular mesh. The update has to be
* exclusive (sychronized with multiple threads)
*/
protected synchronized void updateFacetDistancesSequentially(
List<MeshPoint> facetVertices,
List<Double> facetDistances,
MeshFacet comparedFacet) {
boolean firstComparison = facetDistances.isEmpty();
for (int i = 0; i < vertices.size(); i++) {
Point2MeshVisitor visitor = new Point2MeshVisitor(vertices.get(i), relativeDistance, concurrently());
comparedFacet.accept(visitor);
for (int i = 0; i < facetVertices.size(); i++) {
Point2MeshVisitor visitor = new Point2MeshVisitor(facetVertices.get(i), relativeDistance, false);
comparedFacet.accept(visitor);
double dist = visitor.getDistance();
updateDistances(facetDistances, firstComparison, dist, i);
}
}
/**
* Sequentially updates distances of particular mesh. The update has to be
* exclusive (sychronized with multiple threads)
*/
protected synchronized void updateFacetDistancesConcurrently(
List<Double> facetDistances,
List<Future<MeshVisitor>> results) {
boolean firstComparison = facetDistances.isEmpty();
try {
for (int i = 0; i < results.size(); i++) { // wait ntil all computations are finished
Point2MeshVisitor visitor = (Point2MeshVisitor) results.get(i).get();
double dist = visitor.getDistance();
updateDistances(distList, firstComparison, dist, i);
updateDistances(facetDistances, firstComparison, dist, i);
}
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(HausdorffDistMeshVisitor.class.getName()).log(Level.SEVERE, null, ex);
}
}
......
......@@ -10,11 +10,14 @@ import java.util.concurrent.Callable;
* Implement this interface whenever you want to define new algorithm over a mesh.
* </p>
* <p>
* There are two visitation strategies available.
* The {@link cz.fidentis.analyst.mesh.mesh.MeshVisitor#visitMeshFacet} inspects
* the facet immediately. On the contrary,
* the {@link cz.fidentis.analyst.mesh.MeshVisitor#visitConcurrently} enable to
* inspect multiple facets concurretly. The later has to be called from a code like this:
* The visitor can be instatiated either as sequential and concurrent.
* The {@link cz.fidentis.analyst.mesh.mesh.MeshVisitor#visit} inspection method
* of a sequential visitor is applied immediately. On the contrary, if the
* visitor is concurrent and thread-safe, then the methed only stores the inpected
* mesh facet for later concurrent inspection. To trigger the facet inspection,
* a {@link java.util.concurrent.ExecutorService} has to be used to call
* the {@link cz.fidentis.analyst.mesh.mesh.MeshVisitor#call} method asynchronously
* and then wait for results of all triggered visitors.
* </p>
*
* @author Radek Oslejsek
......@@ -32,8 +35,12 @@ public abstract class MeshVisitor implements Callable<MeshVisitor> {
/**
*
* @param concurrently If {@code true} and this visitor is thread-safe, then
* the visitor is applied concurrently on multiple mesh facets.
* @param concurrently If {@code true} and the visitor is thread-safe, then
* the visitor is created as concurent
* (the {@link cz.fidentis.analyst.mesh.MeshVisitor#visit} is not executed
* immediately byt postponed for concurrent asynchronous execution).
* Otherwise, the visitor is created as sequential
* (the {@link cz.fidentis.analyst.mesh.MeshVisitor#visit} is executed immediately.)
*/
public MeshVisitor(boolean concurrently) {
this.concurrently = concurrently;
......@@ -41,9 +48,9 @@ public abstract class MeshVisitor implements Callable<MeshVisitor> {
/**
* Returns {@code true} if the implementation is thread-safe and then
* a single visitor instance can be applied to multiple mesh facets simultaneously.
* <b>a single visitor instance</b> can be applied to multiple mesh facets simultaneously.
* If the visitor is not thread-safe, the concurrent inspection
* via the {@link cz.fidentis.analyst.mesh.MeshVisitor#visitConcurrently}
* via the {@link cz.fidentis.analyst.mesh.MeshVisitor#visit}
* is still possible, but with multiple visitor instances - one for each facet.
* <p>
* Thread-safe implementation means that any read or write from/to the visitor's
......@@ -75,7 +82,9 @@ public abstract class MeshVisitor implements Callable<MeshVisitor> {
protected abstract void visitMeshFacet(MeshFacet facet);
/**
* The main visitation method
* The main visitation method, either invoked immediately (if the visitor
* was created a sequentional) or postponed to later parallel execution
* (if the visitor is thread-safe and has been created a concurrent).
*
* @param facet Mesh facet to be visited.
*/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment