공부/운영체제2011. 7. 10. 11:09


Background
CPU는 메인메모리와 레지스터를 통해 명령어와 데이터를 가져온다.
레지스터의 경우엔 한사이클에 가져올 수 있지만 메모리에서 데이터를 가져오려면 여러 사이클이 필요하다.
이 둘의 속도차이를 줄이기 위해 캐쉬가 있다.

각각의 프로세스는 분리된 메모리 공간에 저장된다.
base register와 limit register를 이용해 다른 프로세스 영역에 침입하지 못하게 한다.
이 두 레지스터는 커널이 관리하고 유저모드에서는 변경을 할 수 없다.

Address binding
메모리 주소를 결정할 때 대개 다음과 같은 과정을 거친다.
프로그램 소스는 변수를 이용해 값에 접근 할 수 있다.(symbolic address) 컴파일러를 통해서 이 symbolic address는 relocatable address로 바뀐다. '예를 들면 모듈로 부터 14byte 떨어진 위치에 있다.' 이런식이다. 그리고 linkage editor와 loader는 relocatable address를 absolute address로 바꾼다.

하지만 항상 이 모든 단계를 거치지는 않는다. compile 시간에 메모리 어디에 프로그램이 올라갈 것인지 알수 있다. 하지만 나중에 시작 위치가 바뀌게 되면 재컴파일 해야 된다. 또 다른 경우로 컴파일 시간에 알지 못하면 컴파일러에 의해 relocatable code가 생성되고 메모리로 올라가는 load 시간에 주소가 결정이 된다. 이 때는 시작 위치가 바뀌게 되더라도 변경 된 값을 적용 시켜주면 된다. 그리고 실행 시간에도 프로세스가 변동가능성이 있을 수 있다. 실행 중에 주소가 결정되게 된다.

Logical vs. Physical Address Space
Logical(virtual) address는 cpu가 생성하는 주소이다.
그리고 Physical address는 메모리가 인식하는 주소이다.
실행 중에 주소가 결정될 경우, Virtual address를 Physical address로 바꿔주는 시스템이 필요하다.
이를 memory-management unit( MMU)가 이 일을 한다. CPU가 logical address를 사용하면 MMU의 relocation register가 메모리에 접근할 수 있는 physical address로 바꿔준다.

Dynamic loading
메모리 공간 활용을 잘 하기 위해 사용. 루틴이 실제 호출 될 때까지 디스크에 있는다. 사용될 때, relocatable linking loader가 호출되어 디스크에 있던 루틴을 메모리로 불러들이고 프로그램 주소 테이블을 수정한다.
사용되지 않는 루틴은 절대 호출되지 않아 메모리 공간을 아낄 수 있는 장점이 있다.

Dynamic linking and Shared Libraries
대개 system library에 사용된다.  각 프로그램마다 실행가능한 이미지 만들 때 library가 복사되어 들어간다면 디스크와 메모리 공간을 낭비하는 셈.
stub가 실행가능한 이미지에 library 대신 들어가서 library가 필요할 때, library가 메모리에 없다면 메모리에 불러와주고, 이미 있다면 연결시켜준다. stub는 이러한 일을 할 줄 아는 코드다.
이러한 dynamic linking(실행중 연결)을 통해 프로세스들은 각자의 library를 가질 필요가 없이 library를 공유할 수 있게 된다.
 
Contiguous Allocation
각각의 프로세스가 메모리에서 하나의 연속적인 공간으로 할당되는 것. 

Memory Mapping and Protection
limit register와 relocation register를 이용해서 메모리 매핑과 보호를 한다.
limit register는 logical address의 범위값이고, relocation register는 가장 작은 물리 주소를 가진다.
logical address는 반드시 limit register보다 작아야 한다.
MMU는 relocation register를 통해 동적으로 물리주소로 매핑할 수 있다.

Dynamic Storage-Allocation Problem
여러개 프로세스가 메모리 할당되고 해제되고 하다보면 프로세스 사이에 메모리 공간이 있게 되고 그 공간이 크면 새로운 프로세스를 그 공간에 할당할 수 있다. 작은 공간은 못쓰고 빈 상태로 있다. 운영체제는 할당된 공간과 할당되지 않은 공간에 대한 정보를 가지고 있어야 한다.
빈공간을 활용하여 프로세스를 넣는 방법은 세가지 있다. First-fit, Best-fit, Worst-fit.
First-fit은 처음 발견한 공간이 프로세스를 넣을 만큼 충분하다면 다른 빈공간 안보고 거기다가 넣고
Best-fit은 최대한 아낄려고 모든 빈공간을 다 본 후 가장 알맞은 빈공간에다가 넣고
Worst-fit은 모든 빈공간을 다 보고 가장 큰 공간에다가 넣는 것이다.

Fragmentation
프로세스가 메모리에 계속 들어갔다 나왔다하다 보면 빈공간이 너무 작아 어떤 프로세스라도 들어갈 수 없는 것들이 많이 생기게 된다. 이걸 External Fragmentation이라 하고
Internal Fragmentation은 요청한것보다 약간 크게 할당될 수도 있는데 일부분을 안쓰게 되는 현상이다.
그래서 압축을 하자니 실행중인 프로세스들을 일시중지해야 되므로 현실적으로 어렵다. 그래서 나오게 된것이 Page와 Segmentation 개념이다.

Paging
프로세스가 메모리에 연속적으로 저장되지 않아도 된다. 쪼개져서 저장될 수 있다.
paging의 기본방식은 물리주소공간을 frame단위로 쪼개고, 논리주소공간을 frame과 같은 사이즈로 쪼갠다. 논리주소공간의 쪼개진 조각들은 page라고 한다.
메모리 할당이 고정된(page, frame)단위로 이루어 지므로 external fragmentation이 없다. Internal은 마지막 프레임에서 발생할 수 있다.
대신에 주소 변환과정이 좀 복잡해진다.
page가 어느 frame인지 알려주는 page table이 있어야 한다. 프로세스별로 하나씩 있다.
하드웨어가 페이지방식을 지원. -> CPU가 주소를 생성할 때, page number와 page offset으로 나눠서 생성한다. page number로 frame의 시작 위치를 찾고, offset과 시작 위치를 합쳐서 정확한 메모리 주소를 알수 있다.

페이지 테이블은 레지스터에 저장하면 빠르겠지만 요즘 컴퓨터는 페이지개수가 많기 때문에 메모리에 저장한다. (PCB)
하드웨어는 Page-table base register(PTBR)를 제공해서, 페이지테이블이 빨리 바뀔 수 있게 도와준다.
페이지 테이블 참조하느라 한 바이트 읽는데 메모리를 2번 참조하게 된다. 문제다.
하드웨어는 이 문제에 대해 Translation Look-Aside Buffer(TLB)라는 작은 캐쉬를 제공한다.
TLB에 페이지정보가 있으면 메모리에서 읽어오는 것보다 빨리 물리메모리 주소값을 얻을 수 있다.

Protection
page 환경일 경우 memory protection은 각 프레임의 protection bit를 붙여서 수행한다. bit값들은 page table에 저장된다.
이 bit를 이용해서  vaild/invalid를 설정한다. vaild이면 이 페이지가 프로세스의 logical address임을 의미한다. 따라서 사용하지 않는 logical address일 경우엔 invalid로 설정되어 잘못된 메모리에 접근 하는 것을 막아준다.
대개 많은 프로그램들이 자신에게 할당된 logical address를 다 사용하지 않는다. 그래서 모든 logical address를 포함하는 page table은 공간 낭비가 심하다. 그래서 몇몇 시스템은 하드웨어가 page-table length register(PTLR)을 제공하여 페이지 사이즈를 정하게 된다.

Shared Pages
프로세스들이 공통된 page를 따로 메모리에 로드 시킬 필요없이 서로 공유할 수 있다.
page를 read만 할 거면 공유해도 문제없다.(프로세스의 code부분)

Structure of the Page Table
32bit 주소 공간이면, 
페이지 테이블 사이즈게 엄청 커지게 된다.
페이지 크기가 4KB(2^12)이면 페이지 테이블의 엔트리 수는 2^32/2^12 = 2^20 이고 엔트리 하나당 크기가 4byte면 페이지 엔트리 크기는 4MB. 페이지테이블 사이즈가 크면 메인메모리에 한번에 담기 어렵다.

Hierachical Paging
페이지 테이블을 몇단계로 나눈다. 계층화한다.
outer page table들을 통해 page table에서 물리주소를 알아낸다. 

Hashed Page Tables
주소공간이 32bit보다 클 경우 대개 hash를 사용한다.
논리 주소의 페이지숫자를 hash function에 넣어 나온 해쉬값으로 물리 주소공간의 프레임 위치를 알아낸다.

Inverted Page table
프로세스마다 페이지 테이블이 하나씩 있을 경우, 하나의 페이지 테이블은 자신이 사용하는 물리 메모리 이외에도 사용하지 않는 물리 메모리 정보도 가지고 있으므로 많은 공간을 차지할 수 있다. 이런 문제를 해결하는 방법으로 프레임(실제메모리)을 엔트리로 가지고 있는 페이지 테이블을 사용할 수 있다. 테이블이 하나면 된다. 테이블의 하나의 엔트리에는 <process-id, page-number, offset>으로 이뤄져 있어 cpu가 logical address <pid, p, d>를 보내면 이 페이지 table에서 맞는 <pid, p>를 찾고 이 엔트리는 physical address로 정렬되어 있기 때문에 테이블에서의 위치값이 frame의 번호가 된다.
좋은점은 테이블이 하나면 된다느 것이고 문제점은 찾는데 너무 오래 걸린다는 것이다. 그리고 shared page 구현이 어렵다.

Segmentation
유저 관점에서 본 메모리 매핑 기법.
프로그램을 segment들의 집합으로 본다.
segment는 함수, 스택, symbol table(변수이름, 함수이름) 등 사용자가 프로그램을 봤을 때 나눠지는 것들이다.
paging과 구현방식이 비슷하다.
Logical address는 <segment-number, offset>으로 표현되고
Segment table이 있다. table entry에는 base와 limit가 있다. base를 통해 physical 메모리의 어디에 놓일지 알 수 있고, limit를 통해 segment의 사이즈를 알 수 있다. 메모리에 segment별로 저장이 되며, segment끼리 침범하지 않도록 보호할 수도 있고, 프로그램끼리도 보호할 수 있고, code나 data를 공유할 수도 있고, 다른 프로그램이 segment를 공유할 수도 있다. segment가 다양한 사이즈이다 보니 external flagmentation 가능성이 있다.

Segmentation with Paging 
Segmentation과 paging을 둘다 이용한 메모리 매핑 기법.

참고사이트
http://bywords.tistory.com/70 

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

File System  (0) 2011.07.13
Virtual Memory  (0) 2011.07.13
7장 Deadlock  (0) 2011.07.09
6장 Synchronization  (0) 2011.07.04
Process scheduling  (0) 2011.07.03


Posted by skyjumps
공부/알고리즘2011. 7. 9. 22:49


Dynamic programming은 문제를 subproblems로 쪼개서 문제를 푸는 방식이다.

subproblem들이 독립적이면 divide-and-conquer 방식으로 풀 수 있고
독립적이지 않으면 dynamic programming을 한다.
독립적이지 않은 것의 의미는 sub problems가 subsub problems를 공유하는 것이다.
dynamic programming 알고리즘은 같은문제를 또 풀지 않기 위해서 subproblem을 한번만 풀고, 그 결과를 table에 저장한다. 그리고 나중에 필요할 때, 테이블을 참조해서 값을 가져온다.

 Dynamic programming은 최적화 문제(optimization problems)를 푸는데 이용된다.
솔루션은 여러개이지만 그중에 최적화 된 값(최소값 or 최대값)을 가진 솔루션은 하나다. Dynamic programming으로 그 솔루션을 찾는다.

문제 푸는 4가지 단계 
1. optimal substructure를 구한다.
2. recursive solution을 구한다. 
3. optimal solution의 값을 bottom-up 방식으로 계산한다.
4. 계산된 정보로 optimal solution을 구한다.

optimal solution의 sub solution도 optimal solution이다.

overlapping subproblems
순환적인 알고리즘이 같은 문제를 계속 반복하여 방문할 때.

참고 
cs.kangwon.ac.kr/~ysmoon/courses/2011_1/alg/06.pdf

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

Data Structures for Disjoint Sets  (0) 2011.07.11
Greedy Algorithms  (0) 2011.07.11
11장 Hash Table  (0) 2011.07.08
8장 Sorting in Linear Time  (0) 2011.07.03
7장 Quicksort  (0) 2011.07.03


Posted by skyjumps
공부/운영체제2011. 7. 9. 15:13


blocked 프로세스가 서로 필요로 하는 자원을 가지고 있을 때.

System Model
시스템은 자원(씨피유 사이클, 메모리 공간, I/O 디바이스 등)들로 이루어져 있다. 
각각의 자원은 여러개의 인스턴스가 있다.
프로세스가 한 자원 type의 인스턴스를 요구하면 그 타입의 어떤 인스턴스라도 그 요청을 수행할 수 있다.
자원을 사용하고 나서는 반드시 반환해야 한다.

Deadlock Characterization
네가지 조건이 동시에 발생했을 때 Deadlock이 발생할 수 있다.
1. Mutual exclusion(리소스가 여러 프로세스에 의해 공유될 수 없다.)
2. Hold and wait (하나 이상의 리소스를 가지고 있는 채로 다른 자원을 획득하기를 기다리는 것)
3. No preemption (중간에 리소스를 뺏기지 않는 것. 작업을 마치고 내놓는 것)
4. 기다리는 프로세스들이 사이클을 이룰 때. p0는 p1이 가지고 있는 리소스를 원하고, p1은 p2, p2는 p0.

일반적으로 사이클이 없으면 데드락이 없다. 사이클이 있으면 데드락 가능성이 있다. 하지만 있어도 반드시는 아니다. 하나의 자원 type에 여러개 인스턴스가 있는 경우 데드락이 생기지 않을 수도 있다.

Methods for Handling Deadlocks
시스템이 데드락 상태에 빠지는 것을 허용하지 않도록 하는 것.
시스템이 데드락 상태에 빠지는 것을 허용하나, 그것을 감지하고 회복하는 것.
데드락 상태에 빠지면 그 문제를 무시하고 데드락이 발생하지 않은 것처럼 행동하는 것.

Deadlock Prevention
4가지 데드락 발생 조건 중에 최소한 하나라도 성립하지 않게 하기.
mutual exclusion
read-only 파일은 프로세스 여러개가 동시에 접근해도 상관없다.
하지만 원래 공유가 불가능한 자원들이 있다.

Hold and wait
프로세스가 어떤 자원을 요청하기 전, 아무 자원도 가지지 않은 상태가 되도록 한다.
낮은 자원 이용률, starvation 가능성이 있다.

No preemption
프로세스가 어떤 자원을 요청했으나 받지 못하고 기다려야 한다면 지금 가진 모든 자원을 버리고 wait 상태가 된다.
모든 필요한 자원을 얻었을 때 다시 시작된다.

Circular wait
모든 자원에 순서를 매긴다. 높은 숫자의 자원을 가지고 있는 프로세스가 낮은 숫자의 자원을 가지지 못하도록 한다.

Deadlock Avoidance
어떤 리소스를 할당하고 해제하는지 순서를 안다면, 즉 리소스가 어떻게 요청되는지 추가적인 정보를 안다면
미래에 발생할 수 있는 deadlock문제를 사전에 방지할 수 있다.
가장 간단하고 효과적인 방법은 프로세스가  각 type별 최대로 필요한 리소스의 수를 정하는 것이다.
리소스 할당 상태를 조사하여 circular-wait condition이 발생하는지를 알아본다.
리소스 할당 상태는 이용가능한 자원의 수, 할당된 자원의 수, 프로세스의 최대 요구 자원의 수로 정의된다.

Safe state
데드락을 피하도록 자원을 할당받는 프로세스순서 정하기.
이러한 순서를 safe sequence라고 하고
safe sequence에서 한 프로세스가 요구하는 리소스가 (1)현재 이용가능한 리소스와 (2)이전 순서의 프로세스가 가진 리소스의 합보다 작으면 그 프로세스는 요구하는 리소스를 모두 받을 수 있음을 의미한다. 이전 순서의 프로세스는 작업이 끝난뒤 리소스를 반환할 것이기 때문이다.

시스템이 safe state에 있으면 데드락이 발생하지 않을 것이고, unsafe state에 있으면 데드락 가능성이 있지만 반드시 발생하지는 않는다.
따라서 Deadlock Avoidance는 시스템을 항상 safe state한 상태로 유지시키는 것이다.

Resource-Allocation Graph Algorithm
리소스와 프로세스의 관계를 그래프로 표현.

출처 : vidyaprasar.dei.ac.in

점선은 프로세스가 자원을 요청한 상태이다.
할당할 때 cycle이 되는지 조사한다.

Banker's Algorithm
각 리소스 타입마다 인스턴스가 여러개 일때의 알고리즘.
1. 각 프로세스는 각 리소스 타입별로 최대 필요한 인스턴스 수를 가지고 있어야 한다.
2. 이 숫자는 시스템의 전체 자원의 수를 넘지 않아야 한다.
3. 프로세스가 리소스들을 요청할 때, 시스템은 이 자원 할당이 시스템을 safe state하게 하는지 조사해야 한다.
4. 조사 결과 safe state이면 할당
5. unsafe state이면 다른 프로세스가 자원을 방출할 때까지 기다린다.

Safety Algorithm
모든 프로세스의 현재 필요한 자원을 현재 이용가능한 자원으로 처리할 수 있는지 조사.
Dijktra

Deadlock Detection
시스템이 데드락 prevention이나 avoidance한 알고리즘을 제공하지 않으면 detection이라도 제공해야.
wait-for graph

출처 : academic.udayton.edu
resource allocation graph에서 리소스 타입만 제거한 것.
사이클이 생기는지 조사.

Detection algorithm

모든 프로세스에 대해서 현재 이용가능한 자원으로 요청된 자원을 처리할 수 있는지 조사.
하나라도 처리못하는 프로세스가 있으면 그 프로세스는 데드락에 빠진 것. 다른 프로세스들이 완료해서 충분한 리소스를 반환해서 데드락이 깨질 때까지 대기상태에 들어감.
데드락이 자주 발생하면 자주 detection 알고리즘을 수행해 주어야 한다.

자원 할당 요청이 들어오고 즉시 처리할 수 없는 경우마다 이 알고리즘이 호출 될 수 있다.
성능우려 때문에 한시간마다 한번씩, 또는 CPU 이용률이 40퍼센트 이하로 떨어졌을 때 호출하는 방법이 있다.

Recovery from Deadlock 
모든 deadlock 된 프로세스들을 죽이는 방법 - 많은 비용.
사이클이 제거될 때까지 한번에 한 프로세스만 죽이기 - 하나 죽일때마다 detection 알고리즘 호출해야 되서 성능 저하. 그리고 죽이는 것도 어렵다. 그 프로세스가 파일을 수정중이었다면?
그래서 이 방법을 쓴다면 잘 선택하는 것이 중요. 최소비용을 선택
프로세스 우선순위, 프로세스 진행율, 얼마나 많은 혹은 어떤 타입의 리소스가 사용되었는지, 완료하려면 얼마나 많은 리소스가 필요한지, 얼마나 많은 프로세스가 종료될 것인지,  프로세스가 interactive인지 batch인지.
Recovery의 세가지 이슈
죽일 프로세스 선택, Rollback(현재 실행중인 프로세스들의 상태 정보를 다 기억해줘야 되는지), Starvation(한 프로세스만 자꾸 리소스를 뺏겨서 victim이 될 때) 

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

Virtual Memory  (0) 2011.07.13
8장 Memory-management strategies  (0) 2011.07.10
6장 Synchronization  (0) 2011.07.04
Process scheduling  (0) 2011.07.03
Multithreaded Programming  (0) 2011.06.30


Posted by skyjumps
공부/알고리즘2011. 7. 8. 12:00


1. Direct-address tables
키가 n개 있으면 테이블의 크기도 n개
키를 테이블에서 찾는 것, element를 삽입하는 것, 삭제하는 것 모두 running time O(1)
전체 키에서 실제 사용되는 키가 적을 경우 공간 소비가 심하다.
O(1)를 유지시키면서 공간을 줄일 수 있는 방법이 없을까?

2. Hash tables
Hashing
키를 해쉬함수에 넣어서 나온 값으로 hash table에 들어갈 위치를 정하는 것.
Collision
두 키의 Hashing 결과 같은 위치를 가질 때
테이블의 크기가 키크기보다 작기 때문에 collision을 피할 수 없다. collision을 최소화하도록 한다.
어떻게? Hashing function을 잘 만들기.

Collision이 발생하였을 때 해결하는 방법

i) Channing
두 키가 해시테이블에서 같은 위치(collision)일 경우 리스트에 element를 추가한다.
리스트가 길 경우 찾는 시간이 늘어난다. 

load factor
해쉬테이블의 성능 분석 척도
α = n/m (엘리먼트 갯수/슬롯의 갯수)
worst case
모든 키가 테이블의 한 슬롯에만 들어갈 때.

ii) Open addressing
모든 값들이 해시테이블 내에 저장된다. 리스트가 없고 테이블 밖에 element가 저장되지 않는다.
element를 찾을때까지 table slot을 조사한다.
load factor가 1을 넘지 않는다.
포인터 안써도 되고, 리스트일때 사용되지 않던 메모리 공간을 slot으로 이용할 수 있다.

probe : 삽입할 때 slot이 비어있는지 아닌지 확인하는 것.
probe sequence에 따라 slot을 조사한다.

Deletion : search할 때 멈추는 것을 막기 위해서 비워두지 않고 'Deleted' 같은 특별한 표시를 해놓는다.

probing 방법
i) Linear probing
h(k')에 값이 있으면 (h(k') + i) mod m 을 조사(i는 0,1,2,3, ... m-1)
단점
primary clustering : 채워져 있는 slot들이 한곳에 모일 가능성이 높다. i번째까지 가득찬 slots이 있을 때 다음 slot이 가득찰 확률은 (i+1)/m이기 때문에. 평균 search 시간이 늘어난다.

ii) Quadratic probing
h(k, i) = (h'(k) + c1*i + c2*i^2) mod m을 이용
단점
linear probing의 primary clustering은 발생하지 않지만
secondary clustering이 발생. 즉 두 키가 같은 해시값을 가지면 probe하는 위치가 같다.
linear probing처럼 처음 probe 하는 위치가 모든 probing sequence를 결정한다.

iii) Double hashing
h(k,i) = (h1(k) + i*h2(k)) mod m
h1에 의해 같은 값을 갖게 되더라도 h2에 의해 다른 값을 가져서 다른 해쉬값을 가질 수 있다.
따라서 h2가 모든 테이블의 slot를 탐색할 수 있도록 잘 설계되어야 한다.
예를 들어 h1(k1) = 0 이고 h2(k1) = 2일 경우 홀수 slot만 간다.

3. Hash functions
각각의 키가 hash table의 slot에 고르게 들어가도록 hash function을 만든다.
The division method
key k를 m으로 나눈 나머지값이 해쉬값이 된다.
i) m이 2^p 일때,
h(k)의 값은 k의 뒷부분 p bits이다.
ii) m이 2^p-1 일 때,
k는 2^p진법으로 표현 가능하다.
k의 자리수만 바꾼 값들은 k와 해시값이 같다. (각 자리를 modular한 합이 같기 때문에)

좋은 m값
2의 지수승과 가깝지 않은 소수

The multiplication method
key값에 소수인 A를 곱해서 나온 수에서 소수부분에 m을 곱하여 나온 수에서 정수부분이 헤시값이 된다.


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

Greedy Algorithms  (0) 2011.07.11
Dynamic Programming  (0) 2011.07.09
8장 Sorting in Linear Time  (0) 2011.07.03
7장 Quicksort  (0) 2011.07.03
Heapsort  (1) 2011.06.30


Posted by skyjumps
공부/객체지향2011. 7. 7. 22:04


소프트웨어 개발

1. 특징리스트

2. 유스케이스 다이어그램

3. 문제점 분해하기
코드에 관한 것으로 어떻게 기능을 분해할지에 대한 것.
4. 요구사항
고객이 소프트웨어를 어떻게 사용할지에 대한 것.
5. 도메인 분석

6. 사전 설계

7. 구현

8. 4~7 반복

9. 완성

시스템에서 특징은 시스템이 해야 하는 것이며, 시스템이 어떻게 사용되어야 하는지 보여 주는 유스케이스에 항상 반영되지는 않는다. 간접적으로 사용된다.

문제점을 분해하고 유스케이스를 요구사항으로 바꿀 때, '문제 이해하기' 단계가 들어갈 수 있다.

 

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

9장 반복하기, 테스팅하기  (0) 2011.07.03
8장 디자인 원리들  (0) 2011.07.02
7장 아키텍쳐 (architecture)  (0) 2011.06.30
6장 큰문제 해결하기  (0) 2011.06.29
5장 좋은디자인 = 유연한 소프트웨어  (0) 2011.06.28


Posted by skyjumps
공부/JAVA2011. 7. 7. 21:48


http://www.eclipse.org/forums/index.php/m/525050/

상대경로로 했더니 java.io.filenotfoundexception가 나고 절대경로로 하면 괜찮아서 이유를 검색해보니 루트디렉토리가 내가 생각한게 아니었다.

이클립스가 자바클래스를 돌릴 때 현재 경로는 프로젝트의 루트 리렉토리이다. 프로젝트 소스트리의 루트디렉토리가 아니다.
즉 class폴더가 현재경로가 아니라 프로젝트 폴더가 현재경로이다.
나는 class 폴더에 파일을 넣어서 계속 읽을수 없다는 예외가 발생한 것이었다. 

파일시스템의 경로로 읽는 것보다 
getResourceAsStream을 써서 클래스패스로부터 파일을 읽으라고 한다. 

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

Thread  (0) 2011.06.30


Posted by skyjumps
공부/운영체제2011. 7. 4. 01:07


Background

공유 자원에 동시에 접근하는 것은 data inconsistency(데이터 불일치) 문제를 야기할 수 있다.
bounded buffer 문제는 n개 버퍼에 기껏해야 n-1개 아이템만 들어갈 수 있다.
counter 변수를 사용해서 n개 아이템이 들어갈 수 있도록 해보자.
그러면 counter++, counter-- 가 atomically하게 수행되어야 한다.
atomic operation은 인터럽트없이 명령이 완전히 수행되는 것을 의미한다.
counter++와 counter--는 컴퓨터에서 3개 명령으로 처리한다. (counter에서 레지스터로 값을 읽어오고, 레지스터 값을 1 증가하고, 레지스터 값을 counter변수에 넣기) 따라서 중간에 인터럽트가 되면 counter에 원하지 않는 값이 들어간다.
Race condition
여러 프로세스가 공유자원에 동시에 접근하는 상황
이러한 상황을 막기 위해 프로세스들이 synchronized 되어야 한다.

The Critical-section problem
 
공유 자원을 접근하는 코드부분.
한 프로세스가 critical section 부분을 실행중일 때 다른 프로세스가 공유자원을 접근하지 못하도록 해야 한다.
세가지 요구사항
1. mutual exclusion
한 프로세스가 critical section에서 수행중일때, 다른 프로세스들은 그들의 critical section을 수행할 수 없도록.
2. progress
critical section 밖에서 수행중인 프로세스들은 다른 프로세스가 그들의 critical section으로 들어가는 것을 방해할 수 없다.
3. bounded waiting
한 프로세스가 자신의 critical section에 접근하려고 하는데 다른 프로세스가 계속 사용중이라면 기다리는 시간이 한정되어 있다. 

첫번째 알고리즘
mutual exclusion인데, progress가 아니다. Pi가 critical section에 들어가지 않았는데도 Pj가 한번 더 들어갈 수가 없다.

공유데이터 이외에도 전체 코드를 보호할 수 있는데 이는 성능이 떨어진다.

두번째 알고리즘
mutual exclusion이지만 progress가 아님. 둘다 동시에 손들면 deadlock발생 가능성.

세번째 알고리즘
첫번째, 두번째 알고리즘을 합침. 3개 모두 만족

Bakery Algorithm
프로세스에게 번호표를 나눠준다. 가장 작은 수를 가진 프로세스가 critical section에 들어갈 수 있다.
번호는 항상 증가한다.


Synchronization Hardware

하드웨어로 critical section 문제 처리
critical section 들어갈때 인터럽트 disable, 나올때 enable.

Test and Set
특별한 하드웨어 명령어.
atomically하게 실행

Swap

위 두 알고리즘은 mutual exclusion 요구사항은 만족하지만 , bounded-waiting 요구사항은 만족하지 못한다. 운이 나쁘면 계속 못들어간다.


Semaphores and Mutexes

이전 solution들은 더 복잡한 문제에는 적합하지 않다.
세마포어는 OS에서 지원하고 하드웨어나 소프트웨어적으로 구현할 수 있다.
wait(S) 와 signal(S)함수는 atomic하게 실행된다.
while로 구현한 세마포어의 장점은
반응 속도가 빠르다는 점이고 단점은
while로 인해 cpu time을 낭비한다는 것이다. 이러한 종류의 세마포어를 spinlock이라고 부른다.

busy waiting을 피할 수 있는 세마포어
블락을 이용.
블락된 프로세스들의 리스트가 있다.
프로세스가 critical section을 벗어나면 signal을 통해 리스트에서 하나를 깨워준다.
PCB의 link field를 이용해 쉽게 구현가능.
FIFO 큐를 이용해서 bounded waiting 보장.
하지만 세마포어의 사용은 특정 큐 전략에 의존해서는 안된다.
wait와 signal 함수는 atomic하게 실행되어야 한다.
싱글 프로세서의 경우에는 그 프로세서가 인터럽트 못걸게 막으면 된다.
하지만 멀티 프로세서는 모든 프로세스를 막아야 하니 어렵고 성능이 떨어진다.
while로 구현한 세마포어를 사용할 경우 atomic하게 실행된다.
대개 프로그램을 잘짜면 long waiting이 드물다. 

Deadlocks and Starvation
두개 이상의 프로세스가 이벤트를 무한히 기다릴때, 그 이벤트는 기다리고 있는 프로세스 중의 하나가 생성할 수 있는 것일때. 이러한 상황을 Deadlock.

Starvation
무한 블락킹에 빠질경우. 프로세스가 세마포어에서 무한정 기다리게 된다. 예) 리스트가 LIFO일 때, Starvation의 가능성 있다.

두종류의 세마포어
Counting semaphore
세마포어 값(S)이 1보다 큰 값을 가질 수 있다.
critical section에서 여러개의 프로세스가 동시에 실행가능

Binary semaphore
세마포어 값이 0,1만 가진다.
구현이 쉽고
counting semaphore를 구현할 수 있다.??

Mutex
세마포어의 일종
binary 세마포어
소유권의 개념을 가지고 있음.(lock을 건 task만 unlock을 할 수 있다.)
주로 thread간 동기화에 쓰인다. 

Classical Problems of Synchronization

1. Bounded-Buffer using semaphores.
생산자는 empty 감소, full 증가.
소비자는 empty 증가, full 감소.

2. Readers-Writers Problem
버퍼는 하나이고 리더와 라이터는 여러명 일때 버퍼에 어떻게 access하나?
reader를 존중했을 때
writer가 버퍼 사용을 허락받았으면 readers는 기다림.
다른 리더가 버퍼 사용하고 있어도 리더들은 안기다려도됨.
writer가 unbounded waiting에 빠질 수 있음.

writer를 존중했을 때
writer가 빨리 수행될 수 있도록.
writer가 기다리고 있을 때는 어떤 새로운 reader도 buffer에 접근할 수 없다.
reader가 unbounded waiting에 빠질 수 있음.

둘 다 starvation 문제가 있다.

Dining-Philosophers Problem
하는 일이라곤 생각하고 먹을 줄만 아는 5명의 철학자.
둥그런 탁자에 젓가락이 5개밖에 놓여져 있지 않고
배고프면 양옆에 있는 젓가락 2개를 집어야 먹을 수 있다.
하지만 하나 밖에 못집는 상황이 발생.
deadlock과 starvation이 발생할 가능성이 있다.

젓가락 갯수만큼 세마포어가 있을 경우
5명 동시에 젓가락을 하나 집었을 경우 데드락발생

해결방법
철학자 4명만 테이블에 앉게 하기
양쪽 젓가락이 모두 이용가능할때만 집기
홀수 철학자는 왼쪽 젓가락을 먼저 집고 그다음 오른쪽 젓가락을 집는다. 짝수 철학자는 왼쪽 젓가락을 집고 그다음 오른쪽 젓가락을 집는다.

Condition Variable

 어떤 공유 데이터가 특정 상태에 이를 때까지 자신의 실행을 block하게 해준다.
mutex와 함께 사용된다.
mutex는 공유 데이터의 접근을 제어하고
condition variable은 쓰레드가 어떤 공유데이터가 특정한 상태에 이를때까지 wait하게 한다.
condition variable에 의해 wait된 쓰레드는 다른 쓰레드가 공유 데이터에 접근할 수 있도록 자동으로 mutex를 언락한다.
다른 쓰레드에 의해 호출된 signal에 의해 wait하고 있던 그 쓰레드는 다시 꺠어나 mutex를 lock한다.

Conditional variable을 사용하지 않으면 공유 데이터가 특정한 상태에 이르렀는지 계속 조사해야 하므로 쓰레드낭비다.



참고사이트: http://4ellene.net/tt/961 

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

8장 Memory-management strategies  (0) 2011.07.10
7장 Deadlock  (0) 2011.07.09
Process scheduling  (0) 2011.07.03
Multithreaded Programming  (0) 2011.06.30
Process Concept  (0) 2011.06.28


Posted by skyjumps
공부/알고리즘2011. 7. 3. 18:57


Lower bounds for sorting
worst case에서 nlgn보다 빠른 comparison sort(원소의 순서를 정할 때 비교만 사용하는 정렬)가 없다.
참고) heap sort랑 merge sort가 worst case에서 O(nlgn)

The decision-tree model

출처 : http://serverbob.3x.ro/IA/DDU0048.html


모든 원소가 구별되는 값(distinct)이라면
input의 모든 원소를 ai <= aj 로 표현할 수 있다.

comparison sort를 decision trees로 볼 수 있다.
내부 노드 (i,j)는 ai<=aj 임을 의미한다.
각각의 잎노드는 input 원소의 순열(permutation)이다.
 
decision tree의 루트부터 leaf까지의 path는 sorting algorithm의 수행하고 같다.
가장 긴 path의 길이는 worst case를 의미한다.
즉, worst case는 트리의 높이와 같다.

모든 comparison sort algorithm은 worst case일 때 Ω(nlgn) 만큼 비교한다.
n! <= 2^h      (n!은 총 잎의 갯수, h는 트리의 높이)
h>= lg(n!)  
h = 
Ω(nlgn)   ( 왜냐하면 lg(n!) = Θ(nlgn) )

Counting sort
n개의 입력원소가 정수이고 범위가 0부터 k(k<=n)일 때라고 가정한다.
"입력원소 x는 x보다 작은 원소의 수가 i-1개 라면 정렬후에는 i에 위치해야 한다." 라는 원리
집합 A의 원소의 범위가 0~k일 때, 집합 A의 원소의 값이 집합 C의 i와 같으면 Ci값에 1을 추가한다. 집합 C는 A의 원소의 범위가 0~k이므로 k+1크기의 배열이면 된다. C는 A원소의 횟수를 저장한 집합이 된다. C'는 C의 누적합이다. (C'[i] = C[0] + ... + C[i]) 
이 C'를 이용해서 A를 정렬을 할 수 있다. C'i의 값이 a라고 하면 이는 i보다 작거나 같은 값이 집합 A에 a개 있다는 소리다. 그래서 i가 들어갈 자리는 a가 될수 있다.
Stable(입력값이 같은 값이 있을 때 그 순서를 결과값에도 유지 시키는 것)하게 하기 위해서 A의 맨 끝에 있는 원소부터 C'를 이용해서 위치를 찾는다.
수행시간
Θ(n+k)
Θ(k) : C를 0으로 초기화
Θ(n) : A를 스캔하면서 C에 카운터를 증가.
Θ(k) : C를 스캔해서 C' 구하기
Θ(n) : C'과 A를 이용해서 정렬된 집합 B를 구하기. B[C'[A[j]] <- A[j]
k가 O(n)이면 수행시간은 Θ(n)!

Radix sort
n 자리수 숫자들이 있을 때 각 자리수끼리 정렬.
1) 최대유효숫자 -> 최소유효숫자
최대유효숫자부터 정렬. 이전 그룹을 유지하면서 정렬을 해줘야 바르게 정렬이 된다. 
2) 최소유효숫자 -> 최대유효숫자
최소유효숫자부터 정렬.

정렬할 때 stable한 sort 알고리즘을 쓴다.

각 자리수의 범위가 k일 때 d 자리인 n개의 수를 radix sort한 수행시간은?
k가 안크면 counting sort 사용하면 된다.
Θ(d(n+k))           (n+k을 d번한거)
d가 상수고, k = O(n)일 때 radix sort는 linear한 소트이다.

b-bit인 수 n개를, r<=b일 때, r개씩 자르고 radix-sort로 정렬했을 때 수행시간은?
Θ((b/r)(n+2^r)) time.
b/r은 d이고 2^r은 k.
예를 들면
32bit를 8bit씩 4개로 나눠서 4자리씩 radix sort.
r=8, b=32, k는 8bit로 0부터 2^8-1까지, 0부터 255까지 표현할 수 있으니 256개 필요하고, b/r=4, n+2^r = n+256.

Θ((b/r)(n+2^r))을 최소화하는 r
1. b < floor(lgn) 일 때
r<=b 이므로 (n+2^r)은 Θ(n)
그래서 r=b일때, (b/b)(n+2^b) = Θ(n) 

2. b >= floor(lg n) 일 때
r=floor(lg n)을 선택는 것이 최적이다. (b/lgn)(n+2^(lgn) = (b/lgn)(2n) = 
Θ(bn/lg n)
r이 floor(lg n)보다 커지면 2^r은 기하급수적으로 증가하고
r이 floor(lg n)보다 작아지면 b/r은 커지고 n+2^r 은
Θ(n)이 된다.

따라서 1,2 종합해보면 r=lg n씩 자를 때가 최적이다.

Radix sort가 퀵소트보다 좋을까?
Radix sort는
Θ(n)이고 퀵소트
는 Θ(nlgn) 이니 radix sort가 더 좋을 것 같다.
퀵소트보다 각단계(pass)의 횟수가 작을 수가 있지만 Θ(n)에 감춰진 상수값이 클 수가 있다. 즉, Radix sort의 각각의 pass에서 오래 걸릴 수 있다. 그리고 퀵소트는 하드웨어 캐쉬를 더 효과적으로 사용해서 더 빨리 처리된다. 그리고 Radix는 sort in place가 아니다. 정렬하면서 중간값을 저장할 공간이 더 필요하다. 이런점에서 메모리가 좋다면, in-place 알고리즘인 퀵소트가 빠르다.
퀵소트와 캐쉬 locality를 설명한 글 참고
http://soyoja.tistory.com/248#comment1449755



 

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

Dynamic Programming  (0) 2011.07.09
11장 Hash Table  (0) 2011.07.08
7장 Quicksort  (0) 2011.07.03
Heapsort  (1) 2011.06.30
4 Recursion  (0) 2011.06.28


Posted by skyjumps
공부/객체지향2011. 7. 3. 15:38


반복작업을 통해 소프트웨어를 만든다.
큰 그림에서부터 거기서 나눠진 조각들에 대해 반복적으로 작업한다.

특징주도개발(Feature driven development)
고객이 원하는 기능의 한 조각을 선택하고 그것이 완성될 때까지 작업하는 것

유스케이스 주도 개발(Use case driven development)
하나의 완전한 경로를 시작에서 끝까지 코드로 구현.

두가지 방법 모두 고객이 원하는 것을 개발하는 데 초점을 맞추고 있다.

특징 주도 개발
하나의 특징을 결정했다면, 다시 그 특징에대한 분석을 한다.
반복적인 분석. 트리처럼 깊히 분석할수록 세부적인 기능들이 나오는 것을 상상.

고객을 만족시키기 위해 테스트 시나리오를 만든다.
모든 가능한 사용 방법으로 테스트한다.
잘못된 사용 방법에 대해서도 테스트 한다. 이는 초기에 오류를 잡도록 해줄 것이다.

테스트 주도 개발
테스트를 먼저 작성하고 이 테스트를 통과할 수 있도록 소프트웨어를 개발한다.

실제 대부분의 소프트웨어 분석 설계는 다양한 접근 방식을 혼용하여 사용한다. 예) 유스케이스 주도 개발로 시작하여 다음 작업은 유스케이스에서 작은 특징 하나를 선택(특징 주도 개발)해서 개발. 이 특징을 어떻게 구현할지 확인하기 위해 테스트 주도 개발 사용.

각 테스트는 기능의 한 부분에 초점을 맞춘다.

설계방식을 결정할 때( 예) 공통점과 캡슐화 중에서 하나 선택해야 할 때.) 어느 방법이든 항상 트레이드오프(trade off)가 있다. 장점이 있지만 단점도 있는.

반복해서 작업할 때마다 기존의 설계방식을 재평가하고 더 나은 방향으로 변경하는 것을 두려워하지 마라.

약정에 의한 프로그래밍(contract), 방어적 프로그래밍(defensive)
약정에 의한 프로그래밍을 할 때, 문제 상황을 어떻게 다룰 지 합의하기 위해 고객의 코드와 같이 작업하는 것.
방어적 프로그래밍을 한다면, 고객이 어떠한 일이 발생되기를 원하건 간에, 고객이 안전한 응답을 얻도록 확인할 것.
 

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

10장 종합하기  (0) 2011.07.07
8장 디자인 원리들  (0) 2011.07.02
7장 아키텍쳐 (architecture)  (0) 2011.06.30
6장 큰문제 해결하기  (0) 2011.06.29
5장 좋은디자인 = 유연한 소프트웨어  (0) 2011.06.28


Posted by skyjumps
공부/운영체제2011. 7. 3. 02:58


CPU Scheduler
상태가 ready인 프로세스큐에서 하나 선택.
스케쥴링 결정은 프로세스가 (1) running에서 waiting으로 바뀔때, (2) running에서 ready로 바뀔 때, (3) waiting에서 ready로 바뀔때, (4) 종료될 때 nonpreemptive(자발적으로 cpu를 내놓는것)하게 발생한다. 다른 경우는 preemptive(cpu를 빼기는 것)이다.

preemptive 스케줄링의 문제점
공유데이터 일관성이 깨질 가능성 (한 프로세스가 data를 업데이트하는 중에 다른 프로세스한테 cpu 뺏기고 그 프로세스가 그 data를 읽으려고 할 때)
커널데이터의 일관성이 깨질 가능성
예) 커널이 I/O queue를 바꾸고 있었다. 다른 프로세스에게 cpu를 뺏겼다.
시스템콜을 호출할때 그것이 완료되기까지 다른 프로세스가 돌아가지 않도록 하거나, I/O block을 하는 방법이 있다.

Dispatcher
스케줄러가 프로세스를 결정하고 cpu에게 넘겨주는 작업
context switching.
user mode로 바꿈. 스케줄러는 커널에서 작동하므로.
user program에서 다시 시작할 곳의 위치로 jumping

어떻게 하는 것이 좋은 스케줄링인지 결정하는 기준
좋은 스케줄링일 수록 CPU가 노는 일 없게 한다.
Throughout - 임의 시간동안 처리가능한 프로세스갯수. 최대화
Turnaround time - 프로세스의 제출부터 종료까지 경과되는 시간. 최소화
waiting time - 프로세스가 레디큐에 머물러 있는 시간. 최소화
response time - 프로세스가 만들어졌을때부터 실행하기까지 걸리는 시간. 최소화.

First-Come, First-Served(FCFS) Scheduling
선착순방식.
프로세스 도착 순서에 따라 성능이 좌우.
CPU burst(설명, 간단하게 요구하는 시피유 시간)가 큰 프로세스가 들어오면 average waiting time이 커짐.

Shortest-Job-First (SJF) Scheduling
CPU burst가 가장 작은 프로세스를 실행하도록 스케줄링
2가지 방식이 있다.
nonpreemptive - process에게 한번 cpu가 주어지면 cpu burst가 완료될때까지 cpu를 뺏기지 않는다.
preemptive - 새로운 프로세스가 현재 실행중인 프로세스의 남아있는 burst time보다 작은 burst time를 가지고 있다면 cpu를 빼았는다.

Priority scheduling
우선순위에 따라 CPU를 주는 것.
Preemptive, nonpreemptive가 있다.
SJF도 우선순위 스케줄링 방식(cpu burst time이 작을수록 우선순위가 높은것)이니 위에 것이 이해가 될 듯.
문제점
Starvation - 낮은 우선순위는 영원히 실행 안될 가능성이 있다.
해결책 - aging. 프로세스의 우선순위를 시간이 지나면 올려준다. 나이먹는 것처럼.

Round Robin (RR)
각 프로세스가 작은 단위의 CPU time을 얻는다.
한 프로세스가 cpu 사용시간이 지나면 그 프로세스는 preempted 되고 레디큐의 끝에 추가된다.
보통 average turnaround time은 SJF보다 길지만, response time은 짧다. interaction이 중요한 프로그램에게는 이 방식이 좋을수도.

Multilevel queue
레디큐는 여러개의 큐로 나눠진다.
예) foreground용, background용
각각의 큐는 스케줄링 알고리즘을 가지고 있다.
예) foreground(RR), background(FCFS)
큐들 사이에도 스케쥴링이 있다.
예) fixed priority scheduling(foreground queue의 우선순위가 background queue의 우선순위보다 높아서 높은 우선순위의 프로세스가 무조건 cpu를 뺏어올 수 있도록), Time slice(각각의 큐마다 CPU time을 할당한다. foreground에는 80%, background에는 20% 이런식으로) 

Multilevel Feedback Queue
프로세스가 큐들 사이를 이동 할 수 있는 것.
한 프로세스가 CPU를 너무 많이 잡아먹었다싶으면 낮은 우선순위 큐로 내려보내는 것.

리눅스에서의 스케줄링 정책
출처 : http://kldp.org/node/18841
SCHED_OTHER
: 일반적인 process/thread 의 정책. priority를 0만 가질 수 있음. timeshared.

SCHED_FIFO
: realtime을 위한 정책. priority 1~99. timeshared 아님. 오직 더 높은 priority를 가진 task에게만 선점됨. block, yield, terminate되기 전까지 계속 실행.

SCHED_RR
: realtime을 위한 정책. priority 1~99. 동일한 priority를 가진 waiting SCHED_RR task와 timeshared. timeshare할 대상이 없을 때 SCHED_FIFO와 동일하게 동작.
 

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

7장 Deadlock  (0) 2011.07.09
6장 Synchronization  (0) 2011.07.04
Multithreaded Programming  (0) 2011.06.30
Process Concept  (0) 2011.06.28
2장 System Structures  (0) 2011.06.25


Posted by skyjumps