Hallo zusammen,
ich habe nach gescheiterten Versuchen ein performantes Conway's Game of Life zu implementieren das ganze neu geschrieben und versucht es mit mehr als 2 Threads umzusetzen. Bis dahin hat's auch noch ganz gut geklappt, nur wollte ich das Zeichnen des Feldes jetzt eben auch noch aufteilen, und dabei ist mir evtl. ein Deadlock untergekommen.
Nur bin ich mir da nicht so sicher, ich sehe nämlich den konkreten (Denk-)Fehler nicht, nur dass es eben nicht läuft.
Also, hier mal der gesamte Code:
Klasse Conway:
World:
RenderAssistant:
Der Fehler müsste entweder in World oder RenderAssistant liegen, da ich ab der funktionierenden Version an Conway nichts geändert habe. Der Vollständigkeit halber habe ich halt mal alles gepostet.
Ach, der Konsolenoutput ist eine endlose Reihe von
.
ich habe nach gescheiterten Versuchen ein performantes Conway's Game of Life zu implementieren das ganze neu geschrieben und versucht es mit mehr als 2 Threads umzusetzen. Bis dahin hat's auch noch ganz gut geklappt, nur wollte ich das Zeichnen des Feldes jetzt eben auch noch aufteilen, und dabei ist mir evtl. ein Deadlock untergekommen.
Nur bin ich mir da nicht so sicher, ich sehe nämlich den konkreten (Denk-)Fehler nicht, nur dass es eben nicht läuft.
Also, hier mal der gesamte Code:
Klasse Conway:
Java:
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
public class Conway extends JFrame implements Runnable
{
public static final String prefix = "Beta";
public static final String edition = "MT";
public static final String version = "2.0";
public static final int SCALE = 1;
public static final int WIDTH = 1800;
public static final int HEIGHT = 900;
public static final boolean RANDOMIZED = false;
public static final int BORDER = 20;
private volatile boolean running = true;
private World map;
public Conway()
{
super("Conway's Game of Life" + " " + edition + " " + prefix + " " + version);
map = new World(WIDTH, HEIGHT);
setSize(WIDTH*SCALE + 2*BORDER, HEIGHT*SCALE + 4*BORDER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setBackground(Color.WHITE);
setLocationRelativeTo(getParent());
setResizable(false);
setVisible(true);
}
public static void main(String[] args)
{
Conway con = new Conway();
Thread thread = new Thread(con, "Conway");
thread.start();
}
public void run()
{
map.start();
while(running)
{
tick();
System.out.println(getName() + " completed tick");
}
}
private void tick()
{
repaint();
}
public void paint(Graphics g)
{
map.paint(g);
}
public void quit()
{
map.quit();
running = false;
System.out.println("All threads should be terminated...");
System.exit(0);
}
}
World:
Java:
import java.util.Random;
import java.awt.*;
import java.awt.image.BufferedImage;
public class World extends Thread
{
private int width, height;
private boolean[][] map, nextMap;
public volatile boolean done = false;
private volatile boolean running = true;
private Random rnd;
private RenderAssistant[] assistants;
private BufferedImage bImage;
public World(int x, int y)
{
super("World");
width = x;
height = y;
map = new boolean[width][height];
nextMap = new boolean[width][height];
int amount = 0;
amount = height%3 > 0 ? height/3 + 1 : height/3;
assistants = new RenderAssistant[amount];
int restHeight = height;
for(int i = 0; i < amount; i++)
{
assistants[i] = new RenderAssistant(width, restHeight/(amount - i), i+1);
restHeight -= restHeight/(amount - i);
}
rnd = new Random();
if (Conway.RANDOMIZED)
{
for(int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
map[i][j] = rnd.nextBoolean();
}
}
}
bImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2 = bImage.createGraphics();
g2.setColor(Color.RED);
g2.fillRect(0 , 0, width, height);
}
public void run()
{
while(running)
{
tick();
System.out.println(getName() + " completed tick");
}
}
private synchronized void tick()
{
while(done)
{
try
{
wait();
}
catch(InterruptedException e)
{
}
}
nextStep();
int tHeight = 0;
for(RenderAssistant r : assistants)
{
int y = r.getY();
boolean[][] temp = new boolean[width][y];
for(int i = 0; i < width; i++)
{
for(int j = 0; j < y; j++)
{
temp[i][j] = nextMap[i][j + tHeight];
}
}
r.setWork(temp);
tHeight += y;
}
map = nextMap;
/*
for(int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
if(map[i][j] != nextMap[i][j])
{
map[i][j] = nextMap[i][j];
if(map[i][j])
{
bImage.setRGB(i, j, 0xff000000); //black
}
else
{
bImage.setRGB(i, j, 0xffff0000); //red
}
}
}
}
*/
done = true;
notify();
}
public synchronized void paint(Graphics g)
{
while(!done)
{
try
{
wait();
}
catch(InterruptedException e)
{
}
}
Graphics2D g2 = bImage.createGraphics();
int tHeight = 0;
for(RenderAssistant r : assistants)
{
g2.drawImage(r.getResult(), 0, 0, null);
tHeight += r.getY();
}
g.drawImage(bImage, Conway.BORDER, 3*Conway.BORDER, width*Conway.SCALE, height*Conway.SCALE, null);
done = false;
notify();
}
public void quit()
{
for(RenderAssistant r : assistants)
{
quit();
}
running = false;
}
private int getAmountOfNeighbors(int x, int y)
{
int n = 0;
if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
{
for(int i = x-1; i <= x+1; i++)
{
for(int j = y-1; j <= y+1; j++)
{
if(getState(i, j))
{
n++;
}
}
}
}
return n;
}
private boolean getState(int x, int y)
{
if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
{
return map[x][y];
}
else if (Conway.RANDOMIZED)
{
return false;
}
else
{
return true;
}
}
private boolean getNextState(int x, int y)
{
if ((x < width) && (y < height) && (y >= 0) && (x >= 0))
{
if(getState(x, y))
{
switch(getAmountOfNeighbors(x, y) - 1)
{
case 2: case 3: {return true;}
default: {return false;}
}
}
else
{
if(getAmountOfNeighbors(x, y) == 3)
{
return true;
}
return false;
}
}
return false;
}
private void nextStep()
{
for(int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
nextMap[i][j] = getNextState(i, j);
}
}
}
}
RenderAssistant:
Java:
import java.awt.image.BufferedImage;
public class RenderAssistant extends Thread
{
private int width, height;
private boolean[][] toRender;
public BufferedImage bImage;
public boolean done, assigned;
public volatile boolean running = true;
public RenderAssistant(int x, int y, int index)
{
super("RenderAssistant " + index);
width = x;
height = y;
toRender = new boolean[width][height];
bImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
}
public int getY()
{
return height;
}
public void run()
{
while(running)
{
render();
System.out.println(getName() + " completed render");
}
}
public synchronized void setWork(boolean[][] work)
{
while(assigned)
{
try
{
wait();
}
catch(InterruptedException e)
{
}
}
toRender = work;
assigned = true;
done = false;
notify();
}
public synchronized void render()
{
while(done || !assigned)
{
try
{
wait();
}
catch(InterruptedException e)
{
}
}
for(int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
if(toRender[i][j])
{
bImage.setRGB(i, j, 0xff000000); //black
}
else
{
bImage.setRGB(i, j, 0xffff0000); //red
}
}
}
done = true;
notify();
}
public synchronized BufferedImage getResult()
{
while(!done)
{
try
{
wait();
}
catch(InterruptedException e)
{
}
}
assigned = false;
notify();
return bImage;
}
public void quit()
{
running = false;
}
}
Der Fehler müsste entweder in World oder RenderAssistant liegen, da ich ab der funktionierenden Version an Conway nichts geändert habe. Der Vollständigkeit halber habe ich halt mal alles gepostet.
Ach, der Konsolenoutput ist eine endlose Reihe von
Code:
frame0 completed tick
Zuletzt bearbeitet von einem Moderator: