'2011/06/30'에 해당되는 글 4건

  1. 2011.06.30 Heapsort 1
  2. 2011.06.30 Multithreaded Programming
  3. 2011.06.30 7장 아키텍쳐 (architecture)
  4. 2011.06.30 Thread
공부/알고리즘2011. 6. 30. 18:58


merge sort와 같이 running time이 O(nlgn)이다.
insertion sort와 같이 sorts in place이다.

Heaps
complete binary tree이다. 높이가 k일 때 k-1까지는 노드가 모두 채워져 있고 마지막 레벨 k부터는 왼쪽부터 오른쪽으로 노드가 채워지는 tree.

참고) full binary tree : 각 레벨에 노드가 꽉 차있는 트리

힙의 종류
max-heaps 과 min-heaps가 있다.

max-heap
부모 노드 값이 항상 같거나 크다. A[Parent(i)] >= A[i]
루트 노드는 최대값이다.
subtree의 루트노드는 그 subtree의 최대값이다.

min-heap
부모노드값이 항상 작거나 같다.
루트노드는 최소값이다.

힙은 배열에 저장할 수 있다.
배열 A[1]에 루트노드가 저장되고 A[2]부터 레벨순으로 왼쪽에서 오른쪽으로 차례대로 배열에 저장된다.
배열에서 노드의 부모값과 자식값을 알 수 있는 방법
Parent(i) = floor(i/2)
left(i) = 2i
right(i) = 2i+1

heap의 높이
각 레벨의 노드 갯수 ; 1, 2, 4, 8 ..... 2^(n-1)
k레벨일 때까지 등비수열 합을 해주면 총 노드 갯수 n = 2^k -1
k = lg(n+1) 따라서 높이 h = θ(lgn)

Maintaining the heap property
Max-Heapify
노드의 왼쪽 오른쪽 서브트리가 max heap인데 정작 노드는 자식노드보다 작을 때 부모는 자식보다 크다는 max heap 속성을 어기므로 만족할때까지 밑으로 내린다. 내려가는 횟수는 아무리 많아도 트리의 높이보다 작다. O(h) = O(lg n)
 
Building a heap
자식을 가진 맨 아래 오른쪽에 있는 노드부터 시작해서 Max-heapify 해준다. (밑에서부터 힙이 이루어지도록 한다.) 다음 max-heapify 해줄 노드 방향은 오른쪽 -> 왼쪽, 아래 -> 위다.
위에서부터 밑으로 내려가는 방식은 힙이라는 것을 보증하지 못하기 때문에 힙이 안만들어 질 수도 있다.

Running time
Upper bound는 Max-HEAPIFY가 O(lg n)이므로 노드 O(n)개에 대해 수행하면 O(nlg n) 이 된다.
Thighter bound를 살펴보면 트리의 아래쪽에 있는 노드는 lg n보다 적은 시간이 들고 이러한 아래에 있는 노드들이 많으므로 tighter bound는 Upper bound 보다 작다. 계산하면 O(n)이 된다. linear time으로 기존의 배열을 힙으로 만들 수 있다.

max힙에서 n번 최대값을 뽑는 비용은? (Heap sort)
O(nlgn)
루트가 최대값이므로 그 값을 뽑고 루트 자리에 가장 낮은 노드를 넣어서 max heapify 한다. 그래서 n-1번 동안 O(lgn) 이므로 O(nlgn)

Priority queue
우선순위 개념을 큐에 도입한 자료 구조. 데이터가 우선순위를 가지고 있고 우선 순위가 높은 데이터가 먼저 나가게 된다. 힙으로 구현할 수 있다.
최대값을 읽는 것은 O(1)이고 읽고 지우는 것은 지우고 나서 Max heapify가 사용되므로 O(lg n)
노드의 키값을 증가시킬때, 바꾼 값이 힙을 깨뜨릴 가능성이 있다. 힙을 유지하기 위해 위로 올라가면서 자기자리를 찾는다. 기껏 올라가봤자 트리 높이 보다 작다. O(lg n)
노드를 삽입할 때는 힙의 맨 마지막에 넣고 힙을 유지하기 위해 노드를 위로 올리면서 자기자리를 찾는다. 이것도 O(lg n)

'공부 > 알고리즘' 카테고리의 다른 글

8장 Sorting in Linear Time  (0) 2011.07.03
7장 Quicksort  (0) 2011.07.03
4 Recursion  (0) 2011.06.28
3장 Growth of Funtions  (0) 2011.06.24
2장 insertion sort, merge sort, binary search, selection sort, bubble sort  (1) 2011.06.23


Posted by skyjumps
공부/운영체제2011. 6. 30. 16:27


Threads란?
CPU 이용의 기본 단위. 스케쥴링의 가장 작은 단위
lightweight process라고 부른다.
코드섹션, 데이터섹션, open files나 signal같은 운영체제 자원을 같은프로세스에 속한 쓰레드들끼리 공유한다.
쓰레드끼리 공유 안하는 것은 Thread Id, stack, register, pc 이다.

참고> 코드영역, 데이터영역, 스택영역, 힙영역
코드영역 : 실행할 프로그램 소스코드
데이터영역 : 전역변수, static 변수
스택영역 : 지역변수, 매개변수, 리턴값
힙영역 : malloc같이 사용자가 할당한 메모리가 여기 저장됨.
참고 사이트 : http://blog.naver.com/PostView.nhn?blogId=ace7min&logNo=18253266

장점
1. 쓰레드 중에 하나가 blocking될 경우 다른 쓰레드가 돌아가기 때문에 프로그램이 계속 돌아간다.
2. 메모리와 자원을 공유한다.
3. 같은 프로세스 내에서 쓰레드 전환이 일어날 경우 프로세스 생성을 하지 않고 context switch overhead 작다.

User threads와 Kernel Threads
1) User threads
user-level의 thread library에 의해 관리된다.
커널로부터 지원이 없다.
장점
쓰레드간 전환할 때 커널 스케쥴러를 호출할 필요가 없기 때문에 빠르다. 커널 스케쥴러를 호출함은 유저모드에서 커널모드로 들어가는 것을 의미한다. 이는 레지스터 교환 등 많은 작업이 일어나게 되므로 느려진다.
단점
한 쓰레드가 system call등을 호출해서 커널로 진입할 때 그 프로세스의 다른 쓰레드도 모두 정지된다. 커널이 쓰레드의 존재를 알지 못하기 때문이다. 

2) Kernel threads
커널에서 사용하는 쓰레드.
장점
쓰레드 단위로 스케쥴링이 되므로 멀티프로세서를 활용할 수 있다.
단점
kernel level에서 동작하기 때문에, user level 쓰레드보다 느리다.

Multithreading Models
1) M-to-one
커널쓰레드 하나에 많은 유저쓰레드
쓰레드 하나가 blocking 당하면 나머지 쓰레드도 blocking.
한번에 한 유저쓰레드만 커널쓰레드에 접근 가능하다.

2) One-to-one
커널쓰레드 하나에 유저쓰레드 하나.
멀티프로세서에 병렬적으로 처리가 가능하다.
커널쓰레드를 만드는데 드는 오버헤드는 프로그램의 성능에 안좋은 영향을 줄 수 있다.

3) Many-to-Many
많은 커널쓰레드에 많은 유저쓰레드가 매핑됨.

참고사이트 : http://kldp.org/node/295/  유명한 곳인 듯
 
1. Thread Issue
한 쓰레드에서 fork 호출 할때, 새로운 프로세스는 부모의 모든 쓰레드를 복사할 것인가, 그 쓰레드 하나만 복사할 것인가?
exec()가 바로 호출되면 모든 쓰레드 복사가 필요없을 것이고 exec()가 바로 호출되지 않으면 필요할 것이다.

2. Thread Issue - signal
Unix 시스템에서 사용되고 프로세스에게 특정한 이벤트가 발생했다고 통보한다.
signal 처리
Default action
프로세스가 시그널처리 핸들러가 없을 경우 커널에 의해 처리
core dump(메모리, 레지스터 값을 알려주고) 종료되는 경우 (Abort), 그냥 종료되는 경우(exit), 무시하는 경우(ignore), 프로세스를 정지하는 경우(stop), 정지되었을 경우 재개하는 경우(continue)가 있다.

시그널 핸들러가 있는 경우
스그널을 받으면 핸들러에 따라 처리.
신호를 블락할 수 있다.
그러나 SIGKILL이나 SIGSTOP은 핸들러 처리나 블락 못하고 받아들어야 한다.

한 프로세스에 쓰레드가 여러개 있을 경우 시그널이 어디로 전달되어야 하나 ?
1. 시그널이 적용되는 스레드에게 전달(예 : 동기적 시그널)
2. 모든 스레드에게 전달 (예 : ctrl-c)
3. 프로세스의 특정 스레드에게 전달. 어떤 스레드는 block할 수 있고 어떤 스레드는 accept할 수 있다.
4. 모든 시그널을 받는 지정된 스레드에게 전달.

3. Threading issues - Thread Pool
프로세스 시작시에 쓰레드 미리 생성해서 pool에다가 보관하다가
프로세스가 요청하면 전달한다.
쓰레드가 종료되면 다시 pool로 복귀.
미리 생성해놔서 더 빠르다.
쓰레드 수 제한이 가능해진다. 많은 수의 쓰레드를 동시에 처리하지 못하는 시스템에게는 좋겠지.

4. Threading Issues - Stack overflow
User thread의 스택이 overflow가 날 경우 커널은 알지 못한다.
커널이 protection fault를 감지하고 SIGGEGV 시그널을 해당 프로세스에게 보낸다. 

'공부 > 운영체제' 카테고리의 다른 글

6장 Synchronization  (0) 2011.07.04
Process scheduling  (0) 2011.07.03
Process Concept  (0) 2011.06.28
2장 System Structures  (0) 2011.06.25
1장 Introduction  (0) 2011.06.24


Posted by skyjumps
공부/객체지향2011. 6. 30. 12:05


큰 조각을 작은 조각으로 나누었고 아키텍쳐는 이러한 조각들이 어떻게 연결되는지 그리고 어떤 조각들이 더 중요한지를 알게 해준다. 즉, 무엇부터 시작해야 될지 알려준다.
아키텍쳐 (architecture)
아키텍쳐는 디자인 구조이고 프로그램의 가장 중요한 부분들과 그들 사이의 관계를 명확히 보여준다.
중요한 구성요소들의 관계를 파악하기 위해서는 구성 요소를 알아야 한다.
그래서 그 구성요소부터 파악한다. 가장 중요한 기능에 초점을 맞춘다.

중요한 기능을 정하는 기준.
1. 시스템의 본질이 되는 부분인지. 가장 기본적인 요소.
2. 그 기능이 무슨 의미인지 모를 때.
3. 그 기능을 도대체 어떻게 해결해야될지 감이 안올 때.

중요한 기능을 발견하고 나서 어떤 기능을 먼저 만들지는 위험요소(양이 많아 시간이 오래 걸린다던가, 고객이 시스템을 맘에 들어 하지 않는다던가, 해결못할 가능성이 있다던가 등등 )를 줄이는 방향으로 진행하기만 하면 순서는 상관없다.

시나리오는 중요한 요구사항을 포함한 유스케이스의 특정 경로.
시나리오는 중요한 기능에 초점을 맞춤으로써 위험요소를 줄이는 데 도움이 된다.
시나리오는 빠르게 문제를 해결할 때, 보편적인 요구 사항을 찾는 데 도움이 된다.
유스케이스는 모든 경로를 다루고 있어서 시간이 오래걸리고 형식적일 수도 있다. 처음부터 너무 세세한 내용에 집착하지 말것.
유스케이스를 사용하든 유스케이스 다이어그램을 사용하든 시나리오를 사용하든 사용목적은 고객의 만족이다.
위험을 줄이려면 한번에 하나의 특징에 집중하고, 위험을 줄이는데 도움이 되지 않는 특징들에 너무 연연해하지 말기.

기능이 무슨 의미 인지 모를 때 먼저 고객들에게 물어본다.
고객들의 이야기를 바탕으로 공통점을 찾고 그 특징을 어떻게 구현할 것인가를 정한다.
좋은 디자인은 위험을 줄여 준다. 이 기능이 무엇인지 파악했고 프로젝트 진행 중에 별다른 변경없이 다른 클래스들과 연결될 수 있다.
공통점분석할 때 차이점이 더 많다면 시스템내에서 그 기능을 처리하지 않는 것이 좋은 방법이 될 수 있다. 

'공부 > 객체지향' 카테고리의 다른 글

9장 반복하기, 테스팅하기  (0) 2011.07.03
8장 디자인 원리들  (0) 2011.07.02
6장 큰문제 해결하기  (0) 2011.06.29
5장 좋은디자인 = 유연한 소프트웨어  (0) 2011.06.28
4장 분석  (0) 2011.06.26


Posted by skyjumps
공부/JAVA2011. 6. 30. 02:48


Thread 클래스 상속.
run()함수에서 쓰레드 동작 수행
start()함수로 쓰레드 실행

2가지 방식으로 run함수 제공할 수 있다.
첫번째는 쓰레드 클래스를 상속해서 run함수를 오버라이드.
두번째는 Runnable 인터페이스를 구현.

쓰레드 상태

출처 : http://www.cs.nccu.edu.tw/~linw/javadoc/tutorial/java/threads/states.html

API 보니까 stop, suspend, resume은 위험하다고 쓰지 말라고 하네. 한 15년 된 자료인듯ㅋ

Runnable에서 not runnable로 갈 때는 sleep함수가 호출 되었을 때, 또는 condition variable(공유하구 있는 변수인듯)을 기다릴때, 또는 I/O 처리할때

Dead일 때는 할일 다하고 죽었을 때랑. stop에 의해 죽었을 때. API 문서 보니까 stop 대신에 thread 레퍼런스에 null을 넣으라고 하네.

IsAlive() method : 쓰레드가 살아있는지 확인하는 함수. Runnable일때랑 Not runnable일 때 참.

Thread 우선순위
우선순위가 가장 높은 쓰레드가 선택되어 실행되고 중간에 우선순위가 더 높은 쓰레드가 나오면 교체된다.(preemptive) 쓰레드가 종료되거나 yield()함수로 다른 쓰레드에게 CPU를 넘겨주거나, 무슨 이유로 Not runnalbe이 될 때 낮은 우선순위 쓰레드가 실행 될 수 있다. 쓰레드 2개 이상이 우선순위가 같으면 시스템이 time-sliced일 경우 round-robin 방식으로 수행된다. 즉, 뺑뺑이 돌리면서 실행 된다. time-sliced가 아니면 cpu가 쓰레드 교체 안하고 계속 처리하겠지.

Daemon thread.
다른 스레드에게 서비스를 제공하는 스레드. 그래서 프로세스에 daemon thread 혼자만 남았을 때 존재의 이유가 없어지므로 프로세스가 종료된다.

Thread group
쓰레드를 묶어서 한번에 처리.
처음에 쓰레드 생성할 때 그룹을 지정.
public Thread(ThreadGroup group, Runnable target)
public Thread(ThreadGroup group, String name)
public Thread(ThreadGroup group, Runnable target, String name)
지정 안하면 default 그룹이 됨.
자기가 속한 그룹 찾기
theGroup = myThread.getThreadGroup();

The ThreadGroup Class

출처 : http://www.cs.nccu.edu.tw/~linw/javadoc/tutorial/java/threads/states.html

▶ 쓰레드그룹은 쓰레드를 많이 가질 수 있고, 또한 쓰레드그룹도 가질 수 있다. 
쓰레드그룹은 쓰레드를 관리할 수 있고, 그 그룹에 속한 객체가 자신의 쓰레드그룹의 정보를 알 수 있다. ex) activeCount(), enumerate()
▶ 쓰레드그룹은 그룹레벨에서 유효한 속성 값을 지정하거나 참조할 수 있다. 예를 들면 그룹 속성을 지정할 때 이미 그룹안에 있던 쓰레드들은 영향을 받지 않는다. 새로 들어오는 애들은 영향을 받지만. 예를 들면 setMaxPriority() 함수는 쓰레드나 쓰레드그룹에서 최대로 가질 수 있는 우선순위를 매기는 함수이다. 쓰레드그룹이 setMaxPriority(5)를 하면 그 안에 있는 개별 쓰레드나 개별 그룹이 가질 수 있는 최대 우선순위는 5이다. 하지만 기존에 있던 개별 쓰레드는 자기의 우선순위를 그대로 유지한다. 10이었으면 5로 안바뀌고 10이다. 하지만 새로 들어오는 쓰레드는 영향을 받는다. 그리고 하위 그룹쓰레드의 경우에는 미리 들어와 있던 새로 들어오던 상관없이 부모의 최대우선순위를 준수했다.
▶ 쓰레드그룹은 자기 그룹내에서는 접근제한이 없지만 다른 그룹끼리 정보를 참조 하거나 수정하는 것에는 접근제한이 있다. checkAccess 함수를 이용하여 접근할 수 있는지 없는지 알 수 있다.

Synchronizing Threads
쓰레드들이 데이터를 공유할 경우. 이 데이터들은 동기화 되어야 한다.
Producer/Consumer 문제
producer가 물건을 생산하고 consumer가 그 물건을 소비한다고 할 때, producer와 consumer는 번갈아가면서 물건을 생산 소비 하는 문제. 동기화가 안될 경우 producer나 consumer가 연달아 두 번이상 실행될 경우가 발생한다. 

Race conditions
비동기로 실행되는 쓰레드들이 한 자원에 동시에 접근해서 잘못된 결과를 내는 것.

Monitors
두 쓰레드가 한 자원을 공유할 경우 그 자원의 접근은 반드시 동기화를 해야 하며 이 자원을 condition variable이라 부른다. 자바 랭귀지는 monitors를 사용해서 쓰레드가 condition variable의 동기화 접근을 가능하게 한다.

notify(), wait()함수를 사용해서 producer, consumer가 번갈아 한번씩 물건에 접근하게 한다.

Critical sections
두 쓰레드가 동시에 같은 자원에 접근할 가능성이 있는 코드
자바랭귀지에서는 Critical sections에 synchronized 키워드를 써서 동시 접근을 막는다.
자바에서는 주로 method 에 synchronized를 붙인다. 일부분에도 붙일 수 있으나 객체지향적인 관점에서 프로그램을 유지보수하기가 어렵다고 한다.
쓰레드가 synchronized 함수에 접근할 때 그 쓰레드는 그 객체의 monitor를 얻어서 다른 쓰레드가 그 객체의 synchronized함수를 호출 하는 것을 막는다.
monitor의 획득과 반납은 Java runtime system에 의해 자동으로 이루어 진다.

notify() method
notify() 함수가 호출되면 객체의 모니터를 획득하기 위해 기다리고 있는 쓰레드들 중 하나를 선택하여 모니터를 준다. 모니터를 객체에 접근할 수 있는 허가증이라고 보자.
기다리는 쓰레드가 여러개 있을 때 어떤 객체에게 모니터를 줄것인가는 모른다. Java runtime system 마음이다.
notifyAll()은 기다리고 있는 쓰레드 모두에게 모니터를 얻을 자격을 주는 것이다. 경쟁해서 한놈이 모니터를 갖고 나머지는 다시 기다려야 한다.

wait() method
현재 쓰레드가 wait() method를 호출하면 다른 쓰레드가 notify를 할 때까지 기다린다.
wait()와 notify()을 같이 사용함으로써 자원을 공유하는 쓰레드문제를 처리할 수 있다.

Monitors and the notify() and wait() methods.
현재 쓰레드가 wait() 함수가 호출 될 때 다른 쓰레드가 synchronized 함수에 들어갈 수 있도록 monitor를 내놓는다. 그래서 notify 받으면 다시 모니터를 획득한다.


 출처 : http://www.cs.nccu.edu.tw/~linw/javadoc/tutorial/java/threads/deadlock.html


Posted by skyjumps