2017-09-01 TIL

프로세스

  • 실행 중인 프로그램(Program in execution)
  • 1개의 CPU는 1개의 프로세스만 실행 할 수 잇다.
  • IO는 CPU를 기준으로 어마어마하게 느린 작업이다.
  • 그래서 IO가 발생하면 그 프로세스는 일단 Wait 상태가 되고 IO가 끝나면 다시 ready가 된다.
  • 프로그램은 모두 자신만의 PC를 가지고 있다. (다른 프로세스를 실행하다 다시 돌아오면 어디서 시작해야하는지 알아야한다.)
  • 프로세스는 논리적인 단위
  • Linux : task_struct (double Linked List로 구성됨) 현재 시작하고있는 task를 가리키는것이 current
  • 리눅스는 CPU숫자만큼 프로세스가 있다?
  • 컴퓨터는 시간의 흐름에 따라 실행된다.

프로세스가 생기는 절차

  • 컴퓨터가 시작하면 1번 프로세스가 생기고 이 프로세스가 새끼를 친다.
  • fork()를 부르는 주체는 나.
  • 자식 프로세스를 만들때 자신이 fork()를 해서 자신을 하나 더 만들고 (부모와 자식이 같다 - 클론) 그리고 exec()를 실행하면 자식프로세스가 바뀐다.
  • 터미널은 배쉬쉘이란 것을 사용하는데 명령어를 치면 배쉬가 클론이 되고 변환되서 실행되서 종료된다.
  • OS에는 매우 비싼 작업이다. (프로세스를 새로 실행시키는 작업은 비용이 크다.)

Process Control Block

  • 프로세스의 메타데이타
  • 모든 프로세스는 자기만의 메타데이타를 가진다.
  • PC(Program Counter) - 프로그램의 실행 시점
  • CPU - Register - L1 Cache - L2 Cache - Memory - HDD
  • CPU가 어마어마 하게 빠르기 때문에 그 속도의 갭을 해결하기 위해 레지스터 - 캐쉬 가 있다.
  • CPU는 ADD, SUB, MUL, DIV, SHIFT, AND, OR … 의 일을 한다.

컨텍스트 스위치

  • 한 프로세스에서 다른 프로세스로 작업을 변경하는 것.
  • 작업을 변경할때는 PC를 저장해놔야 한다.
  • 많이 하면 좋지 않다.(오버헤드가 굉장히 크다.)
  • 프로세스가 시간의 흐름에 따라 돌아가다가 인터럽트가 발생하였을 때 프로그램카운터를 저장하고 Idle 상태의 프로세스를 실행 시킨다. 그때 그 Idle상태의 프로세스의 정보를 로드하고 다 로드 되면 프로세스가 실행된다. (로드 되는시간엔 CPU는 아무것도 못한다 이것이 컨택스트 스위치 오버헤드라 한다.)
  • 실행시간(execute time)을 얼마를 할건지가 중요하다. (느리게하면 반응속도가 느리다.)

쓰레드

  • 프로세스가 비용이 커서 스레드가 생겼다.
  • 프로세스 내에서 실행되는 흐름의 단위(정확한 정의, 시간의 흐름)
  • 프로세스는 최소 하나 이상의 스레드를 갖는다.
  • 라이트 웨이트 프로세스(가벼운 프로세스라고 생각해도 무방하다.)
  • 프로세스에 비해 생성과 컨택스트 스위치가 빠르다. (비용이 적다.)
  • 논리적인 쓰레드는 PC의 흐름이다.
  • 고유한 메모리 영역이 없고 자신의 PC와 레지스터만 가지고 있기에 빠르다.
  • 부모 쓰레드가 끝나면 자식쓰레드 까지 전부 종료된다.

병렬프로그래밍 (동시성 보장)

  • 함수형 프로그래밍은 기본적으로 동시성이 보장된다.
  • 각각이 스스로 계산한 다음에 마지막에 더하는게 최고의 효율의 병렬프로그래밍.(그래도 99%)
  • 공통적으로 동작하지않는 부분이 1% 생기기 때문에 이것이 성능에 영향을 미친다.

동시성과 병렬성

  • 동시성 - 여러기능이 한 번에 실행 되는 것.
  • 병렬성 - 한프로그램의 동시에 여러개 실행.
  • 요즘 세상에서는 동시성을 고려한다.

쓰레드프로그래밍

  • 비결정적 프로그래밍 - 어떤놈이 언제 실행될지는 아무도 모른다.
  • 디버깅이 어렵다. - 결과가 재현이 어렵다.
  • 동기화하는 부분은 최소화 해야한다. (동기화를 할때는 1개만 동기화메서드를 점유함) ``` package study.thread;

public class ThreadTest extends Thread { public static long totalSum; public long start, end, sum;

public synchronized static long getSum() {
	return totalSum;
}

public ThreadTest(long start, long end) {
	this.start = start;
	this.end = end;
	System.out.println(start + " : " + end);
}

public synchronized static void merge(long sum) {
	totalSum += sum;
}

public void sum() {

	for (long i = start; i <= end; i++) {
		sum += i;
	}
	merge(sum);
}

@Override
public void run() {
	sum();
}

public static void main(String[] args) throws InterruptedException {
	long start = System.currentTimeMillis();
	long max = 2000000000;
	int n = Runtime.getRuntime().availableProcessors(); //		int n= 1;
	long step = max/n;
	Thread[] t = new Thread[n];
	for (int i=0; i < n; i++) {
		t[i] = new ThreadTest(i* step + 1, (i+1) * step);
		t[i].start();
	}

	for (Thread tt : t) {
		tt.join();
	}
	System.out.println((System.currentTimeMillis() - start) + "ms");
	System.out.println(ThreadTest.getSum());

} } ```

암달의 법칙

  • 가장 오래 걸리는 프로그램을 개선해야한다.
  • 무언가를 할때 가장 중요한놈을 고쳐야 한다.

데드락의 3가지 조건

  • mutual exclusion - 상호배제 (한번에 한놈만 들어올 수 있다.)
  • non preemption - 방해 받지않는다.(내가 시작하면 끝나기전에 끝내지않는다.) - 포기하거나 끝내게 하는것(해결법)
  • circular waiting (원형 큐) - 번호를 매긴다. (홀수번은 오른손 짝수번은 왼손)

데드락 피하기

  • 동기화 부분에서 외부 메서드를 호출하지 않는다.
  • 순서를 미리 결정한다.
  • 동기화 코드는 최대한 짧게

동기와 비동기 (Slipp에서 검색!) - 블락과 논블락, 동기와 비동기는 서로 다른축의 이야기다.

  • 동기 -
  • 비동기 -
  • 블락 -
  • 논블락 -

대부분 IO이후의 어떻게 반응을 할건가? IO가 왓을때

  • 블락 - 완료될때까지 기다린다(에러나면 나는것)
  • 논블락 - 오래걸릴것 같으면 하지 않는다. (정상적일때는 읽는다. 기준은 API가 정한다.)
  • 동기 - 끝날때까지 기다림
  • 비동기 - 바로 다음코드를 실행하는데 나중에 콜백을 부른다.(콜백은 내가 실행하는게 아니라 내가 원하는 API가 이것을 호출할때 콜백함수를 등록해주면 자기가 호출한다. - 언제 실행될지 모름)

물리메모리

스레드 추가 자료


어마어마한 시간낭비지만 해보면 OS에 대한 감을 가질 수 있다!

리눅스 오브 스크래치

젠투 리눅스

교학사 리눅스커널 완전정복

concurrent 모델 책

  • 7가지 동시성 모델
  • 자바 병렬 프로그래밍
  • java concurrent 구글링 검색해서 개념만 이해해도 됨.

    쓰레드 예제

    흡혈귀 코드

    생각하는 철학자

Comments