In meiner Anwendung (Bachelorarbeit), habe ich eine sich sehr oft in einer Schleife wiederholende datenunabhängige Aufgabe.
Die Aufgabe ist es den Index des Maximalwertes in einem sehr großen Array zu erhalten.
Weshalb ich den Ansatz der Parallelen Reduktion benutze.
Das Array wird dabei in kleinere Arrays unterteilt auf denen eine vorgegebene Anzahl von Threads arbeitet (Anzahl an CPU-Kernen).
Eine Implementierung mit einfachen Threads ist mir gelungen und war auch nicht sehr schwer.
Jedoch ist der mögliche Performanzgewinn des parallelen Ansatzes nun nicht so hoch, da die Threads jede Iteration neu initiiert werden, da es mir nicht gelungen ist dies mit Deamon-Threads zu realisieren.
Zur Realisierung mit Deamon-Threads habe ich mir eine eigentlich kleine und einfache abstrakte Deamon Thread Klasse geschrieben, welche wie folgt aussieht.
Abstrakte DeamonThread Klasse
package util.threads;
/**
* DeamonThread Class for re-occuring Tasks
*/
public abstract class ADeamonThread extends Thread
{
/**
* flag indicating to start the update method in the endless while loop
* of the run method
*/
private boolean run = false;
/**
* flag indicating if this thread should be stopped
*/
private boolean stop = false;
/**
* Creates a new Deamon thread who needs to be started manually
*
* @param name String
*/
public ADeamonThread(String name)
{
super(name);
this.setDaemon(true);
}
@Override
public void run()
{
while(!this.stop)
{
try
{
Thread.sleep(10);
}
catch (InterruptedException e)
{
System.out.println("Error " + e.getMessage());
}
if(this.run)
{
this.update();
this.run = false;
}
}
this.run = false;
}
/**
* The Method which is executed by the deamon if {@link #activate()} is called
*/
protected abstract void update();
/**
* sets the running flag to true!,
* should be called if arguments are needed!
*/
public void activate()
{
this.run = true;
}
/**
* Stops this thread safely
*/
public void stopSafe()
{
this.stop = true;
}
/**
* Returns true if this deamon thread is currently performing its update method.
* {@link #update()}
*
* @return true if active
*/
public boolean isActive()
{
return this.run;
}
/**
* blocks the calling thread until the current call of the
* update method of this deamon thread has terminated.
* {@link #update()}
*/
public void waitTillFinished()
{
while(this.run) { }
}
}
Implementierende DeamonThread Maxima Klasse
package Cluster.CPU.Threads;
import java.util.List;
import util.threads.ADeamonThread;
import Cluster.ACluster;
import Cluster.Cluster;
/**
* Threaded Cluster Max calculation
*/
public class ClusterMaxDeamonThread extends ADeamonThread
{
/**
* cluster list of this thread
*/
private List<ACluster> clusters = null;
/**
* The Maximum Cluster of this Thread
*/
private Cluster clusterMax = null;
public ClusterMaxDeamonThread(int index)
{
super("CPU ClusterMax Thread: " + index);
this.start();
}
@Override
protected void update()
{
this.clusterMax = new Cluster(null, null, -1.0f);
Cluster cluster = null;
for(ACluster aCluster : this.clusters)
if(aCluster instanceof Cluster)
{
cluster = (Cluster)aCluster;
if(cluster.getValue() > this.clusterMax.getValue())
this.clusterMax = cluster;
}
}
/**
* Activates this DeamonThread to find the current maximum cluster
* of the given clusters
*
* @param clusters List<ACluster>
*/
public void activate(List<ACluster> clusters)
{
this.clusters = clusters;
super.activate();
}
/**
* Returns a Cluster who's value is -1.0f if no cluster has been found!
* @return Cluster
*/
public Cluster getClusterMax()
{
return this.clusterMax;
}
}
Das Problem ist, dass sich das Programm aufhängt, wenn ich mittels der active methode mehrere der DeamonThreads sozusagen aufwecke ihre Arbeit zu tuen, und dann im Hauptthread auf die Abarbeitung der Threads warte. Relevanter Code ab Zeile 18.
Aufrufende Klasse
Cluster[] clusterMaxs = new Cluster[ClusterProcessCPU.CPU_COUNT];
//get tile size each thread works on
int tileSize = Util.getCeil(this.clusters.size(), this.clusterMaxThreads.length);
//tileSize of 1 is checked by if before!!!
int startIdx = 0;
int endIdx = 0;
//activate all threads
for(int t = 0; t < this.clusterMaxThreads.length; t++)
{
startIdx = Math.min(t * tileSize, this.clusters.size());
endIdx = Math.min(startIdx + tileSize, this.clusters.size());
/*
* Activate each Thread with its sub list
*/
this.clusterMaxThreads[t].activate(this.clusters.subList(startIdx, endIdx));
}
//wait for them to finish and get results
for(int t = 0; t < this.clusterMaxThreads.length; t++)
{
this.clusterMaxThreads[t].waitTillFinished();
clusterMaxs[t] = this.clusterMaxThreads[t].getClusterMax();
}
/*
* init clusterMax with first cluster and check last array
*/
Cluster clusterMax = clusterMaxs[0];
for(int i = 1; i < clusterMaxs.length; i++)
if(clusterMaxs**.getValue() > clusterMax.getValue())
clusterMax = clusterMaxs**;
return this.clusters.indexOf(clusterMax);
Ich sehe den Fehler nicht.
Alle Deamon Threads arbeiten auf ihrem eigenen sub Array und der haupt Thread wartet bis all deamon threads mit ihrer arbeit fertig sind.
Wenn ich in meiner abstrakten Deamon Thread Klasse so ändere dass diese einfache Punkte in ihrer while schleife ausgibt, dann funktioniert mein Programm manchmal, eine Erhöhung des Sleep Timeout in der update methode auch.
public void waitTillFinished()
{
while(this.run) { System.out.print("."); }
}
Wäre für Hilfe sehr dankbar.