PainterKarelProgram2 (KarelOOP2)

Retired DISLab
이동: 둘러보기, 찾기
/*
 * Copyright 2020 Sangwon Park @ DISLab, HUFS
 *
 * 10명의 페이트 칠쟁이들이 무작위로 돌아다니며 바닥을 칠하는 프로그램이다.
 * 
 * 서로 부딪혀서 캐럴이 망가지지 않도록 하기 위하여 lock을 준비하였다.
 * 이 lock들은 코너 마다 하나씩 준비되어 있고, 좌표를 이용하여 락을 획득한다.
 * 
 * 락을 거는 프로토콜은 다음과 같다.
 * 1. 앞으로 전진할 위치의 락을 획득한다.
 * 2. 캐럴을 앞으로 한 칸 전진한다.
 * 3. 이전 위치의 락을 해제한다.
 * 
 * 이때 데드락(deadlock)이 발생한다. 보편적으로 락을 이용하면 데드락이 발생할 수 있다.
 * 데드락이 발생하는 경우는 다음과 같다.
 * 1. 예를 들어 두 개의 캐럴 K1, K2가 서로 마주보고 있을 때 서로 상대 위치를 탐할 때
 * 2. 이미 데드락이 걸려 움직일 수 없는 캐럴이 있는 위치에 대한 락을 요구할 때
 * 
 * 즉 데드락은 현재의 스레드가 락을 쥐고 있으면 다른 락을 요청할 때 발생할 수 있다.
 * 
 * 시간이 지나면 모든 캐럴이 상대가 가진 락을 무한정 기다리는 상태가 되어 프로그램이 멈춘다.
 */
package cp.java.week11.thread;
 
import java.awt.Color;
import java.awt.Point;
import java.util.Random;
 
import hufs.dislab.karel.IKarelProgram;
 
class LockManager {
	private LockItem[][] table;
 
	private class LockItem {
		private boolean value = false;
 
		public synchronized void lock() {
			while (value == true) {
				try {
					wait();
				} catch (InterruptedException e) {
				}
			}
			value = true;
			notifyAll();
		}
 
		public synchronized void unlock() {
			value = false;
			notifyAll();
		}
	}
 
	public LockManager(int width, int height) {
		table = new LockItem[width][height];
		for (int i = 0; i < width; i++) {
			for (int j = 0; j < height; j++)
				table[i][j] = new LockItem();
		}
	}
 
	public void lock(int x, int y) {
		//String name = Thread.currentThread().getName();
		//System.out.println(name + ":  lock " + x + "," + y);
		table[x - 1][y - 1].lock();
	}
 
	public void unlock(int x, int y) {
		//String name = Thread.currentThread().getName();
		//System.out.println(name + ":unlock " + x + "," + y);
		table[x - 1][y - 1].unlock();
	}
 
	public boolean peek(int x, int y) {
		return table[x - 1][y - 1].value;
	}
}
 
/**
 * DEADLOCK 발생함. 서로 마주보며 서로의 위치에 대한 Lock을 요청하면 데드락이 발생함.
 * @author Sangwon Park
 * @since KarelOOP 2
 */
@SuppressWarnings("serial")
public class PainterThreadProgram2 extends IKarelProgram {
	public static final int NO_KARELS = 10;
 
	MyKarel[] list = new MyKarel[NO_KARELS];
 
	LockManager lmgr;
 
	class Crazy extends Thread {
		MyKarel karel;
		Random r = new Random();
 
		Crazy(MyKarel karel) {
			this.karel = karel;
		}
 
		@Override
		public void run() {
			while (true) {
				switch (r.nextInt(4)) {
				case 0:
					karel.turnLeft();
					break;
				case 1:
					karel.turnRight();
					break;
				case 2:
					karel.turnAround();
					break;
				}
 
				if (karel.frontIsClear()) {
					Point pt = karel.getLocation();
					Point nextpt = new Point(pt);
					if (karel.facingEast())
						nextpt.x++;
					else if (karel.facingWest())
						nextpt.x--;
					else if (karel.facingNorth())
						nextpt.y++;
					else
						nextpt.y--;
 
					lmgr.lock(nextpt.x, nextpt.y);
					karel.move();
					karel.paintCorner();
					lmgr.unlock(pt.x, pt.y);
				}
			}
		}
	}
 
	static Color[] colors = new Color[] { BLUE, RED, YELLOW, ORANGE, CYAN, GREEN, GRAY, 
			PINK, MAGENTA, LIGHT_GRAY, BLACK, DARK_GRAY, WHITE};
 
	@Override
	protected void onInit() {
		int width = getWorldWidth();
		int height = getWorldHeight();
 
		lmgr = new LockManager(width, height);
 
		list[0] = (MyKarel) getKarel();
		Point pt = list[0].getLocation();
		lmgr.lock(pt.x,  pt.y);
 
		Random r = new Random();
		for (int i = 1; i < list.length; i++) {
			int x, y;
			do {
				x = r.nextInt(width) + 1;
				y = r.nextInt(height) + 1;
			} while (lmgr.peek(x, y));
 
			lmgr.lock(x,  y);
			int dir = r.nextInt(4);
			Color color = colors[i % colors.length];
 
			MyKarel karel = new MyKarel(x, y, dir, color);
			list[i] = karel;
			addIKarel(list[i]);
		}
	}
 
	@Override
	public void onStart() {
		for (MyKarel karel : list) {
			new Crazy(karel).start();
		}
	}
 
	public static void main(String[] args) {
		IKarelProgram.main(args, new MyKarel(1, 1, EAST, BLUE));
	}
}
개인 도구
이름공간
변수
행위
둘러보기
구성원
연구
연구실
기타
도구모음
인쇄/내보내기