PainterKarelProgram3 (KarelOOP2)

Retired DISLab
Swpark (토론 | 기여) 사용자의 2020년 10월 20일 (화) 23:30 버전
(비교) ← 이전 판 | 현재 판 (비교) | 다음 판 → (비교)
이동: 둘러보기, 찾기
/*
 * Copyright 2020 Sangwon Park @ DISLab, HUFS
 *
 * 10명의 페이트 칠쟁이들이 무작위로 돌아다니며 바닥을 칠하는 프로그램이다.
 * 
 * 서로 부딪혀서 캐럴이 망가지지 않도록 하기 위하여 lock을 준비하였다.
 * 이 lock들은 코너 마다 하나씩 준비되어 있고, 좌표를 이용하여 락을 획득한다.
 * 
 * 만약 락을 거는 프로토콜이 아래와 같다면 데드락이 발생한다.
 * 1. 앞으로 전진할 위치의 락을 획득한다.
 * 2. 캐럴을 앞으로 한 칸 전진한다.
 * 3. 이전 위치의 락을 해제한다.
 * 
 * 그래서 위 프로토콜을 사용하지 않고 다음과 같이 동작한다.
 * 1. 앞으로 전진할 위치의 락을 요청한다. 이때 락 요청에 대하여 wait(sleep)하지 않는다.
 *    그러므로 데드락이 발생할 수 없다.
 * 2. 락 획득이 성공할 경우에만 앞으로 전진한다.
 * 
 * 이렇게 하면 시간이 지나도 데드락이 발생하지 않는다.
 */
package cp.java.week11.thread;
 
import java.awt.Color;
import java.awt.Point;
import java.util.Random;
 
import hufs.dislab.karel.IKarelProgram;
 
class NoWaitLockManager {
	private LockItem[][] table;
 
	private class LockItem {
		private boolean value = false;
 
		/**
		 * 락을 걸지 못하면 즉시 함수를 빠져나온다.
		 * 락을 거는 쓰레드를 sleep 상태로 빠뜨리지 않는다.
		 * @return 락 성공 여부
		 */
		public synchronized boolean lock() {
			if (value)
				return false;
			value = true;
			return true;
		}
 
		public synchronized void unlock() {
			value = false;
		}
	}
 
	public NoWaitLockManager(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 boolean lock(int x, int y) {
		//String name = Thread.currentThread().getName();
		//System.out.println(name + ":  lock " + x + "," + y);
		return 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 발생하지 않음.
 * 락을 요청할 때 sleep 상태로 가지 않기 때문임.
 * @author Sangwon Park
 * @since KarelOOP 2
 */
@SuppressWarnings("serial")
public class PainterThreadProgram3 extends IKarelProgram {
	public static final int NO_KARELS = 10;
 
	MyKarel[] list = new MyKarel[NO_KARELS];
 
	NoWaitLockManager 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--;
 
					/*
					 * 락 획득이 성공한 경우에만 앞으로 전진한다.
					 * 그렇지 않은 경우에는 아무 일도 하지 않는다.
					 * 그렇게 함으로써 락 획득이 실패했다고 sleep 하지 않는다.
					 * 즉, 내가 락을 쥐고 있으면서 다른 락을 요청하지 않기 때문에
					 * 데드락이 발생하지 않는다.
					 */
					if (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 NoWaitLockManager(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;
		}
 
		for (int i = 1; i < list.length; i++) {
			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));
	}
}
개인 도구
이름공간
변수
행위
둘러보기
구성원
연구
연구실
기타
도구모음
인쇄/내보내기