ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 시스템 프로그래밍 정리
    @ 16. 1 ~ 17. 1/면접관련 2016. 12. 13. 23:12

    D메인메모리(램) : 컴파일이 완료된 프로그램 코드가 올라가서 실행되는 영역

    어떤 프로그램을 실행했다? 그럼 메모리 위에 올라갔다고 표현


    CPU(중앙처리 장치) 구성

    ALU : CPU내부에서 실제 연산을 담당하는 곳(산술연산, 논리연산)

    컨트롤 유닛 : ALU에게 명령어를 그대로 주면 안된다 왜냐면 이녀석은 연산밖에 할 줄 모르니까..명령어가 무슨뜻인지 몰라

    그래서 이걸 해석하는게 컨트롤 유닛이다. 즉, CPU가 처리해야할 명령어들을 해석하는것이다.

    해석이후에 ALU에게 넘겨준다.

    레지스터 Set : cpu내부에서도 임시적으로 데이터를 저장하기 위한 조그만한 메모리 공간

    컨트롤 유닛이 해석하고 임시로 저장해두면 ALU가 일을 마치고 그걸 읽는다.(근데 저장은 이진데이터 저장을 위한 것이다)


    실행파일 생성과정

    전처리기 -> 컴파일러 -> 어셈블러(바이너리 코드 생성) -> 링커


    1. 전처리기에 의한 치환작업

    #로 시작하는 지시자의 지시에 따라서 소스코드를 적절히 변경하는 작업


    2. 컴파일러에 의한 번역

    소스코드 자체가 컴파일러에 의해서 어셈블리 코드로 번역된다.


    3. 어셈블러에 의한 바이너리 코드 생성

    010101로 바꿈


    4. 링커에 의한 연결과 결합

    프로그램내에서 참조하는 함수나 라이브러리들을 하나로 묶는 작업..

    이 과정이 끝나면 실제로 실행 가능한 실행파일이 생성(물론 바이너리 코드다)


    실행을하게되면 실행파일내의 바이너리 코드가 메모리에 올라가ㅔ 되고 cpu에 의해서 순차적으로 실행되기 시작하는데..

    cpu에서 실행되는 과정의 3단계가 있다.



    1) Fetch : 메모리상에 존재하는 명령어를 cpu로 가져오는것         

    버스로 연결되어있는데.

    2) Decode : 가져다 놓은 명령어를 cpu가 해석하는 단계          

    컨트롤 유닛

    3) Execution : 해석된 명령어를 cpu가 실행하는 것        

    ALU


    알고 넘어가기

    1. ALU와 컨트롤 유닛 기능적 역활

    2. 레지스터의 필요성 : 기본적으로 cpu내에 존재하는 저장장치

    3. fetch, decode, execution 단계 설명

    5. 버스 인터페이스 : cpu내부 및 외부에 있는 요소들은 서로 I/O 버스를 통해서 데이터를 주고 받는다.



    아스키 및 유니코드 관련

    알고 넘어가기

    1. SBCS, MSCS, WBCS의 이해




    32비트 64비트로 나누는 기준은 위에 버스 인터페이스에도 나오는데

    cpu는 I/O 버스를 통해서 데이터를 외부로 전송하기도 하고 CPU내부로 수신하기도 하는데 이때 한번에 전송 및 수신할 수 있는 데이터 크기에 따라 나뉘는것임..

    또 하나의 기준은 데이터 처리능력..

    결국 정리하면

    한번에 송, 수신할 수 있는 데이터 크기와 한번에 처리할 수 있는 데이터 크기를 기준으로 32비트 64비트로 나뉜다.



    64비트에서 포인터만 8바이트임 (32비트는 4바이트) 나머지 는 똑같은

    CHAR 1바이트 SHORT 2바이트, INT 4바이트, LONG 4바이트

    32비트에서는 포인터랑 int랑 같으니까 포인터의 주소를 강제형변환해서 넣어도 되었지만..64비트는 포인터가 8바이트이니까..

    나머지 부분이 잘리게 된다. 위험함..




    1. 메모리에 바이너리 코드로 프로그램이 올라가게 되고

    2. 이걸 I/O버스를 통해서 

    3. CPU로 FETCH하게 되고, 해당명령어는 이때 IR레지스터에 저장됨(다음번에 실행될 명령어를 미리 갖다놓는 용도로 IR를 사용함)

    4. CPU에서는 이걸해석하기 위해서 컨트롤 유닛을 이용해서 DECODE를하고

    5. ALU에서는 이 해석될것을 가지고 EXXCUTION을 해버린다.


    연산결과를 레지스터에 저장하는 이유는 ? 메인메모리에 저장하면 안되??  그러나..그건 복잡해지니까 밖으로 빠지면..

    명령어를 처리하는데 속도도 느림..!!


    int a = 10;    //0x10

    int b = 20;    //0x20

    int c = 0;      //0x30

    이렇게 메인메모리에 할당되었다고 하면 바로 cpu에선 계산 못한다 그 이유는?? cpu내부에선 에셈블리어로 작동하는데 그건

    레지스터에 관련된것이니까..그래서 메인 메모리주소를 레지스터에 저장해서 보내야한다..

    여기서 나오는문제는.. 16비트로 명령어를 구성한다면..(ㅇ요즘은 64비트지??)

    앞에 2비트는 예약 빼고..3비트는 명령어 넣고..다음 3비는 레지스트 넣고..그럼 나머지 8비트로 메모리 주소를 쓴다고 하면

    그 메모리 주소가..0x00ff까지만 전부이다..

    그래서 여기서 등장하는게 메모리 접근방법이 나오는데 이렇게 직접적으로 16비트 명령어 뒤에  메모리 주소를 직접 입력?해서 쓰는게

    Direct 몯ㅡ라고 하고..단점은 위에서 본것처럼 0x00ff이상 안됨(주소값을 명령어에 직접 표현하기 때문이다)

    그리고 Indirect 모드란게 있음.

    직접 가리키는게 아니라 참조하는 형식..포인터 같은거네...(주소를 참조하는 주소~)


    []이건 Indirect 모드임..

    LOAD    r1    0x0010

    MUL    r0,    4,    4

    MUL    r2,    4,    4

    MUL    r3,    r0,    r2


    STORE    r3,    0x0030

    LOAD    r2,    [0x0030]

    ADD    r3,    r1,    r2


    이걸 읽을줄알아야함..



    프로세스란?

    어떤 프로그램 실행을 위해 더블클릭을 한다면, 실행을 위헤 메모리 할당이 이뤄지고 이 메모리 공간으로 바이너리 코드가 올라가고

    이 순간! 부터 프로그램은 프로세스라고 불리게 된다. 즉, 실행중인 프로그램이란 뜻이다.

    하나이상의 프로세스가 있을 수 있다 (윈도우 창 2개를 켠것처럼..)


    메모리 공간에 대한것.

    전역변수나 ,static 변수의 할당위해 존재하는 : Data 영역

    지역변수, 함수호출시 전달되는 인자값 저장을 위해 존재하는 : Stack 영역

    동적할당을 위해 존재한는 : Heap 영역

    아까 바이너리 코드들이 메모리상에 올라간다고 한 : Code영역

    이것이 프로세스의 실체이다..


    혹시..프로세스가 하나이상이라고 해서 위의 메모리 구조가 몇개 구성될까? 하나인가?? 아니다 생성되는 개수에 만큼 생성된다. 

    인터넷창 2개면 2개 메모리 구조가 생성된다.

    혹시 지금 인터넷창이 실행 중에 있다면 CPU를 구성하는 레지스터들은 인터넷창.exe의 실행을 위해 필요한 데이터들로 채워지게 된다.

    이렇듯 CPU내에 존재하는 레지스터들은 현재 실행 중인 프로그램을 위한 데이터들로 채워진다.

    (컨텍스트 스위칭이 왜 느린지에 대한 이야기지..)


    cpu에는 현재의 실행중인 프로그램의 데이터들로 채워진다고 하던데..어떻게 프로그램이 동시에 실행이 가능한가?

    엄청 빠르게 그냥 cpu가 여러개의 프로세스를 번갈아 가면서 실행하는거다..

    그런게 그냥 막 번갈아 갈 순 없잖아..그래서 할당하는 기준이 있는데..공평하게 순서대로 돌아가면서 정해진 시간만큼 CPU를 할당받게 되는데..

    이렇게 프로세서의 CPU할당 순서 및 방법을 결정짓는 일을 가리켜 스케줄링 이라고 한다. 이때 사용되는 알고리즘을 가리켜 스케줄링 알고리즘이라고 한다.

    이 알고리즘을 실제 적용해서 관리하는 운영체제 요소를 가리켜 스케쥴러라고 한다.


    일반적으로 프로그램이 실행되는 과정에서 가장 많은 시간을 할당하는게 I/O에 할당된다(단순히 입력 및 출력을 의미하진 않음..패킷 송수신도 해당되고....웹페이지가 느리게 열린다? I/O가 오래 걸린다는거임..)

    어쩄든 멀티 프로세스 운영체계에서는 프로세스 하나가 계속해서 실행되는것 아님..여러 개의 프로세스들이 돌아가면서 실행되는거임..

    그래서 각각의 상태는 시간 흐름에 따라 변화함..!


    생성 / Ready / Running / Block / 종료 이런 상태가 있음.


    생성되었다고 해서 바로 Running 안됨..Ready임..왜냐면 cpu가 다른 프로세스있을 수도 있다. 생성되었다고 나 실행하라는 깡패짓은 안함..

    .그런데..우선순위가 높은 프로세스가 생기면 낮은 프로세스는 Ready로 들어가고 높은 프로세스가 Running이 되긴함..

    I/O 시간이 길어지면 해당 프로세스는 Block으로 들어가게 된다. 그리고 CPU는 다른 프로세스의 Ready상태를 Running상태로 바꾸러 감

    block상태는 스케쥴러가 선택안함.. ready나 block이나 둘다 프로세스가 실행되지 않는 상태임..block이 끝나면 자동으로 ready


    음..그러니까 아무리 Running인 프로세스가 있어도..예를들어 워드가 Running 상태라고 해도..cpu입장에서는 입력이 드문드문이고..잠시 기다리고 이런시간에 다른 프로세스에 대해서 Running하는거다..cpu 진짜 빠르다 1초면..헐.. 그래서 가능하다 이거임..


    컨텍스트 스위칭

    실행중인 프로세스의 변경은 시스템에 많은 부하를 가져다 준다. 왜냐면 아까 위에 CPU 레지스터들은 ? 현재 실행중에 있는 프로세스 관련데이터들로

    채워지게 된다. 그런데 프로세스가 바뀌면 레지스터들의 내용도 바뀌는데..이전 내용들이 어디로 가서 저장이 될까?

    메모리에 저장하게 된다..레지스터보다 훨 느린 메모리에...

    다시 메모리에서 가져오고 저장하고...이런 반복..

    이런것은 레지스터가 많은 시스템일 수록..프로세스별로 관리되어야 할 데이터 종류가 많을 수록..이것이 단점임..




    커널 오브젝트 / 오브젝트 핸들


    커널 : 컴퓨터를 운영하는 운영체제의 핵심적이 부분..

    모든 운영체제는 커널(Kernel) 위에서 실행된다. 커널이란 운영체제의 핵심으로, 

    (사용자 프로그램과 하드웨어 장치간의 인터페이스...os의 엔진같은? 

    보통은 프로세서 생성 삭제, 메모리 관리, I / O관리 등을 지원하는데..)

    (Kernel은 가상 메모리 관리자를 제어합니다. 그리고, 가상 메모리 관리자(virtual memory manager)는 OS 메모리를 직접 액세스할 수 있습니다. )

    손상되면 블루스크린뜸..


    프로세스 생성의 주체는 운영체제이다. 프로그래머가 아님.. 관리도 운영체제가 함..


    커널에서 관리하는 중요한 정보를 담아둔 데이터 블록을 가리켜 커널 오브젝트라고 한다.

    (음...프로세서가 생성될때마다 프로세스 관리 구조체 변수가 하나씩 생성되고 새롭게 생성된 프로세스 정보들로 초기화되는데..

    이 구조체를 커널 오브젝트라고 하는데...맞나?ㅇㅇ 그래서 결국 프로세스가 생성될때마다 커널 오브젝트도 생긴다!!!!)

    (근데 말이야..프로세스가 생성될때만 커널 오브젝트가 생기는게 아님..쓰레드를 생성할때도 생김....파일을 생성할때도 생김..)

    (그래서 말이야.. 커널 오브젝트는 다양한 종류로 생성이 된다.)

    (윈도우 운영체제는 프로세스  쓰레드 혹은 파일과 같은 리소스 들을 원할히 관리하기 위해 필요한 정보를 저장해야한다.

    이때 데이터를 저장하는 메모리 블록을 가리켜 커널 오브젝트라고 한다)

    커널에서 관리되는 리소스 만큼 커널 오브젝트도 생성된다.



    커널오브젝트는 직접 조작 못함..그래서 핸들받아야함..(이 핸들은 커널오브젝트에 할당되는 숫자에 지나지 않음..)

    오브젝트 핸들이라고도 하지요? 그렇다 그 핸들이다..handle...


    오해하지말자 함수가 호출되어 실행되는 중간에는 절대로 cpu의 할당 시간을 다른 프로세스에게 넘겨주지 않을 거이다.(잘못된 생각임)

    넘겨줌..


    커널 오브젝트는 프로세스에 종속적인 것이 아니라 운영체제에 종속적인 관계로 커널오브젝트의 소멸은 운영체제에 의해 결정이 된다.

    커널 오브젝트는 프로세스에 종속적인 것이 아니라 운영체제에 종속적인 관계로 여러 프로세스에 의해서 접근 가능하다.(물론 핸들받고..함수 호출하는 간접적인 접근)


    그러나 반대로!!! 핸들(핸들테이블)은 운영체제에 종속적이지 않고 프로세스에 종속적이다...


    음..운영체제는 프로세스를 생설할때마다 구분하기 위한 ID를 할당한다..

    뭔소리지 : 

    프로세스 핸들은 프로세스의 커널 오브젝트를 구분짓기 위한 것이고, 프로세스 ID는 커널 오브젝트가 아니라 프로세스 자체를 구분짓기 위한 것이다.


    운영체제가 커널오브젝트를 소멸하는 시기

    아...커널 오브젝트를 참조하는 대상이 하나도 없을떄 소멸시키는것이 가장 이상적임..Usage Count를 사용하는데..(카운트가 0이면 소멸된다)

    프로세서 생성과 동시에 커널 오브젝트의 Usage Count는 1이 된다. 접근 가능한 대상이 늘어날때마다 1씩 증가..

    자식 프로세스가 생기면.. 커널 오브젝트의 카운트는 2로 증가 한다 왜냐면? 자식 프로세스의 핸들을 얻기 떄문이닷..

    여기서 자식 프로세스가 종료되면..? 2가 1로 줄어듬..

    쓰레드가 생성될떄도 카운트가 증가한다 ㅋ 커널 오브젝트 카운트~~ 리소스이니까? 아휴..아닌데...




    프로세스들이 서로 만날 수 없는 이유

    프로세스가 생성될때마다 구성되는 메모리 구조는 구분이 되어이기 때문이다..

    프로세스는 할당된 메모리 공간 이외에 다른 프로세스 영역에는 접근 할 수 없다.


    커널 오브젝트도 두가지 상태를 지닌다. 하나는 signaled (신호를 받는 상태), 또하나는 non - signaled(신호를 받지 않는 상태)

    일단 signaled 상태이면 non - signaled상태로 변경되지 않는다.

    처음 생성되때는 non 으로 생성된다..그러다가 종료되면 signaled로 변경된다. 이는 일종의 약속이다.

    그래서 이런 약속때문에 signaled상태의 프로세스 커널 오브젝트를 확인해보고 종료되었음을 알 수 있다.

    (그래서 그 확인을 위해  waitforsingleobject를 쓰는거임..)

    자식 프로세스가 종료될 떄까지 기다려주는 효과를 얻게 됨..부모가 기다리는거임..



    핸들 테이블?

    우선은 시스템 리소스 생성 과정에서 커널 오브젝트가 생성되면, 생성된 커널 오브젝트를 가리킬 떄 사용되는 핸들이 반환된다는것은 알고있지?


    음..반환받은 핸들은 과연 커널 오브젝트의 메모리 주소를 알고 있을까?

    어떻게 알고 있을까? 이것이 핸들 테이블이 나오게 되는 이유님..

    핸들 테이블은 핸들 정보를 저장하고 있는 테이블로서 프로세스별로 독립적이다!!

    이떄 전달되는게 핸들하고 바로 커널 오브젝트의 메모리 주소다!

    자식 프로세스를 생성한다면..물론 자식 프로세스에 대한 핸들테이블이 생긴다. 독립적이라고 했으니까...

    그런데 자식 프로세스는 부모 프로세스의 핸들 테이블에 등록되어 있는 핸들 정보를 상속 받을 수 있다.

    하지만 모든 핸들 정보를 상속받는건 아니라네..상속 하냐 안하냐를 지정할 수 있고(부모에서) 그리고 그건 자자손손대대로 이어져..ㅋ

    그 설정은? 지정은 프로그래머가 한다.

    그래서 상속되는건 UsageCount가? 증가하지롱 상속안하는건 증가 안함


    조금 정리해보자 여기서..

    프로세스가 핸들을 얻게 되었다는 의미는 핸들 테이블에 해당 핸들에 대한 정보가 갱신(추가)되었음을 의미하는 것..


    부모에서 자식에게 핸들 복사해서 주면 UsageCount증가한다. 복사된 핸들도..반드시CloseHandel해줘야한다.




    프로세스의 스케줄링


    RTOS ? OS

    RTOS가 일반 윈도우 os보다 응답성이 빠르다 그 이유는? 사용목적이 구체적이고 제한적이다 보니 단순하게 디자인되어있어서 그렇다

    Soft RTOS  : 우리가 접하는 대부분..OS

    Hard RTOS : 핵 발전소 같이 데드라인이 명확해야하는것..


    비선점 OS 선점 OS??

    비선점 : 우선순위가 높은 프로세스가 나타나도 바로 대상을 변경하지 않음..

    선점 : 바로 바뀜(스케쥴러가 할일이 많다는 이야기임) 이런 특성은 멀티 프로세스 기반 OS에 적함..


    라운드 로빈 스케줄링 알고리즘..

      - 우선순위 높은게 먼저 실행되는건 알겠는데..똑같으면?? 

    ㅋㅋ 그래서 나온게 라운드 로빈 임..이건 같은 우선순위 프로세스들에게 형평성 유지를 위해 정해진 시간 간격만큼만 실행을 하고

    우선순위가 동일한 다른 프로세스에게 cpu의 할당을 넘기고 있다. 오로지 형평성을 위해서..


    실행의 최소 단위 시간 가격 : 퀀텀 또는 슬라이스

    그래서 동일한 우선순위의 모드 프로세스들은 이 슬라이스를 기준으로 CPU의 할당을 넘긴다.

    그런데..이 슬라이스가 길면 ..예를 들어 마우스로 드래그앤드롭하는데 반응이 늦게 생길수도..

    빠르면? 컨텍스트 스위칭이 자주발생되서 느려짐..


    근데 말이다..스케쥴러가 언제 작동해야할까??  

    1. 프로세스의 실행시간 간격에 해당하는 매 타임 슬라이스마다 스케줄러는 동작해야한다.

    2. 프로세스가 생성 및 소멸될때마다 

    3. 현재 실행중인 프로세스가 블로킹 상태가 되었을때




    스택 프레임 구조다!! 중요함

    함수 호출과정에서 할당되는 메모리 블록을 스택 프레임이라고 한다.(지역변수의 선언으로 인해 할당되는 메모리 블럭)

    쌓아올린 위치 기억하는 레지스터 SP(Stack Pointer)

    FP는 뭐냐..(Frame Pointer라는데..) ??

    단순히 선언된 변수들의 값을 더하진 않음..

    왜냐면 이 연산은 상당한 비용이 드니까..

    단순히 그냥 SP의 위치를 저장할 수 없다..왜냐면 중첩 호출되버리면..??FP의 값은 사라진다~~이전값~~

    해결은 단순함..

    덮어쓰는 문제가 발생하기 전에 FP에 저장된 값을 어딘가에 저장해두면 된다..어딘가? 어디긴 스택이다.


    그러니까 단순하게 정리함

    함수호출시에 현재 스택 프레임을 가리키는 SP레지스터가 있고, 그 레지스터의 값을 함수 매개변수나 인자값들이 들어오기 직전에 증가되기전

    SP가 가리키는 주소값을 FP(프레임 포인터)라는 레지스터에 기록을 한다.! 그리고 또 다른 함수 호출이 생기면 현재 SP위치에 FP포인터가 가지고 있는 주소를 스택에 넣는다(SP가 가리는 위치의 스택 구조에 저장한다)


    함수의 호출이 발생한 위치로 이동해서 명령어의 실행을 이어가겠는가? 그리고 무엇을 조작하면 함수 호출이 완료된 다음에 이동이 발생하기 이전 위치로 ㅇ롬겨가 실행을 이어가는가?

    PC 레지스터가 답이다. pc는 명령어를 실행할 때마다 4바이트(32비트 명령어 기준)씩 증가한다. 이 pc에 함수 호출로 인해 이동해야할 주소값을 저장해 두면 자연스럽게 실행의

    위치는 이동하게 된다. 그런데 pc에 이동해야할 주소값을 저장하기 전에 반드시 해줘야 할일이 있다.! 

    pc값을 백업하는것이다. 그래서 이 값을 스택에 저장해준다. 함수 호출시 스택에 저장해야할 대상이 하나 더 늘어남..




    컨텍스트 스위칭에 소요되는 시간을 어떻게 하면 줄일 수 있을까? 저장하고 복원하는 컨텍스트 정보의 개수를 줄여주면 된다.

    하나의 프로그램에서 둘 이상의 실행 흐름을 두기 위해 만들어진것이 쓰레드이다.

    쓰레드는 스택을 제외한 코드, 데이터, 힙 영역을 공유하게 된다.

    (함수 호출에서 스택 프레임이 또 다른 실행흐름을 나타내는 것처럼 이 스택 메모리가 독립적이라는것은 추가적인 실행 흐름을 만들 수 있다는 의미가 된다. 실행 흐르음의 추가를 위한 최소 조건이 독립된 스택제공이다)


    윈도우에서의 쓰레드

    윈도우에서는 프로세스는 단순히 쓰레드를 담는 상자에 지나지 않는다. 때문에 실제 프로그램의 흐름을 형성하는 것은 쓰레드이다.

    쓰레드의 컨텍스트 스위칭이라면 캐쉬를 비울 필요가 없다(프로세스는 필요함 공유되지 않으니까..)

    또한 윈도우에서는 프로세스는 상태를 지니지 않는다(블럭 레디 런닝..) 오히려 상태는 쓰레드가 가지고 있다.

    또한 스케줄러가 선택하는것도 프로세스가 아니라 쓰레드이다.  윈도우에서 실행의 중심은 쓰레드다!

    그런데 이건있다 컨텍스트 스위칭이 스레드는 당연히 있고 프로세스도 우리가 알고 있는 그대로 있다.


    커널레벨 쓰레드

    쓰레드를 생성해주는 대상이 커널일 수도 있다. 

    쓰레드를 생성 및 스케줄링하는 주체가 커널인 경우 이를 커널 레벨 쓰레드라고 한다.

    유저 영역은 사용자에 의해서 할당되는 메모리 공간을 의미한다.( 프로그램이 동작하기 위해 사용되는 메모리 공간을 이야기 한다.)

    * 유저영역은 코드영역, 데이터 영역, 스택 및 힙역영을 가리켜 이야기 하는 것임.

    * 커널영역은 ? 하나의 프로세스에게 할당된 총 메모리 공간 중에서 유저 영역을 제외한 나머지 영역을 이야기 하는데..

    운영체제 역시 실행되기 위해서는 운영채제 역시도 메모리에 올라가야 하고 또 일반 프로그램처럼 실행되는 과정에서 변수 선언도 하고

    메모리를 동적 할당하기도 한다. 이렇게 운영체제라는 하나의 소프트웨어를 실행시키기 위해서 필요한 메모리 공간..그걸 커널 영역..


    **쓰레드의 실행코드는 유저 영역에 존재할것이고...(프로그래머가 개발하니까..) 그러나 스케줄러와 쓰레드 정보(스케줄링을 하는데 필요한 쓰레드 정보)는 커널영역에 존재한다.  오늘날 대부분 운영체제 리눅스, 윈도우는 레벨 쓰레드를 기반으로 쓰레드 모델을 지원한다.


    유저레벨 쓰레드

    이건 유저영역에서 실행이 된다. 그래서 유저 레벨 쓰레드이다. 

    스케줄러가 스케줄링하는 대상은 프로세스이다. 



    2개의 모드의 장단점

    유저 모드? 커널 모드??(2가지의 구분 영역이 생긴이유는 커널 영역의 보호를 위해서 생긴거임..)

    메모리는 활용 대상에 따라 유저 영역과 커널 영역으로 나뉜다. 

    유저 영역은 사용자가 구 현한 프로그램 동작시 사용하게 되는 메모리 영역이다.

    커널 영역은 운영체제 동작시 사용하게 되는 메모리 영역이다.

    커널이 쓰레드를 지원할 경우 쓰레드 관리가 커널 영역에서 이뤄지기 때문에 커널 레벨 쓰레드라고 하고

    커널이 쓰레드를 지원하지 않은 경우 유저영역에서 쓰레드의 관리가 이뤄지기 때문에 유저레벨 쓰레드라고 한다.


    왜 커널 영역이 중요하냐면, 유저 영역에서 메모리 참조 오류가 난다면 기껏해야 실행중인 프로그램인데.. 커널 영역은 커널의 코드가 실행되는 영역이므로 시스템 전체에 문제를 일으킬 수 있다.

    우리가 구현하거나 사용하는 프로그램은 유저 영역에서 실행되므로 실제로 커널 영역에서 문제를 일으킬 일은 없어 보인다. 그러나 C언어의 특성상 메모리 참조가 용이하기 때문에 보장을 할 수 없게 된다. 그래서 안전성 제공 측면에서 뭔가 다른 방법이 필요하다.(2가지 모드가 그래서 생긴거임)


    이에 등장한것이 커널모드, 유저 모드이다. 일반적으로 유저모드였다가 WINDOWS의 커널이 실행되어야 하는 경우에는 커널 모드로의 전환이 일어난다. 다시 말해서 커널 영역에서 실행이 이뤄져야 할 경우에는 커널 모드로의 전환이 일어나는 것이다.


    windows운영체제 차원에서 제공하는 시스템 함수들 중 일부는 호출 시 커널모드로 동작할 수 있다.

    그래서 모드의 전환이 이뤄지는데 시스템에 ㅈ부담을 주는일이다. 

    아아..커널모드 유저모드를 제공하는 대상은 프로세스다 (윈도우 운영체제가 아니다) 메모리 보호 기능은 cpu에 달려있음..


    커널 레벨 쓰레드 장점 및 단점

    장 : 커널에서 직접 제공해 주기 때문에 안전성과 다양한 기능성이 제공된다.

    단 : 커널에서 제공해주는 기능이기 때문에 유저 모드에서 커널 모드로의 전환이 빈번하게 일어난다. 따라서 이는 성능의 저하로 이어지게 된다.


    유저 레벨 쓰레드의 장점 및 단점

    장 : 커널은 쓰레드의 존재조차 모른다. 오로지 유저모드로 동작하기 때문에 유저 모드에서 커널 모드로의 전환이 필요없다. 성능 굿

    단 : 하나의 프로세스에 3개의 쓰레드가 있다 그중 한개 쓰레드가 만약 커널에 의해서 블로킹 되면 모두 실행안된다. 


    어쩄든 유저레벨은 리눅스 개발자들이 즐겨 쓴다.



    진짜 스레드

    프로세스는 쓰레드를 담는 상자 역활을 한다고 하였는데.. 그럼 프로세스 핸들 테이블도? 쓰레드 핸들 테이블이 되나? 이건 아니다.

    이건 프로세스 꺼다 . 즉 하나의 프로세스에 하나의 핸들 테이블이 존재할 뿐이다.

    음..쓰레드 핸들 테이블이 없지만 그 핸들 테이블이 공유가 된다..

    자식 프로세스 생성되면서 usage count 가 2되는것처럼 쓰레드도 생성되면 usage count가 2가 된다.

    하나는 쓰레드 종료시 감소하고 나머지는 쓰레드 핸들을 인자로 closeHandle함수가 호출될떄 감소..

    그래서 쓰레드도 자식 프로세스 처럼 생성되지마자 closehandle을 바로 호출함.. usagecount를 1로 만듬..




    쓰레드 동기화 문제

    쓰레드 동기화 문제는 컴파일 상태가 아니라 런타임에서 발생하는 오류다


    동기화 ? : 순서가 잘지켜진다 ㅋ;라는 의미가 낫다.

    2가지 관점에 동기화

    실행순서의 동기화  : 반드시 a쓰레드의 결과를 b쓰레드가 받아서 출력하는 경우 반드시 순서가 맞아야한다.

    메모리 접근에 대한 동기화 : 한순간에 하나의 쓰레드만 접근해야 하는 메모리 영역이 존재한다.

    바로 데이터 영역과 힙이다. 

    근데 2가지 나누었어도 보통은 같다고 봄..(개인적생각)


    으아 또 window에서 제공하는 동기화 기법은 주체에 따라 2가지로 나뉘게 된다.

    하나는 유저 모드 동기화

    하나는 커널 모드 동기화


    메모리 영역의 접근을 동기화한다는 것은 : 임계영역의 접근을 동기화 한다는 뜻..

    임계영역이란 : 둘 이상의 쓰레드가 동시에 실행할 경우에 문제가 발생할 수 있는 코드 블록을 이야기 함.


    크리티컬 섹션 동기화

    : 열쇠를 얻은 자만이 임계영역에 들어갈 수 있다.


    인터락 함수 기반의 동기화

    : volatile 키워는 절대로 캐쉬되지 않음. 메모리에 직접 선언된다. 컴파일러 최적화 하지마라

    --------------------------------------------

    뮤텍스

    : 이것도 크리티컬하고 같은 방식의 열쇠다 하지만 이건 커널모드라..그리고 뮤텍스 자체가 커널 오브젝트라..

    waitforsingleobject 함수르 ㄹ임계영역 진입을 위한 용도로 사용가능..

    (인자로 전달된 해당 커널오브젝트가 singled 상태가 되었다면 non - signeld 상태로 변경해준다.)

    (정리한다..종료할때까지 무한정 기다린다.singled상태는 종료상태다. non - signeld 종료상태 아니다 )


    쓰레드는 임계 영역에 들어가기에 앞서 뮤텍스를 획득해야한다. 따라서 뮤텍스 핸들을 인자로 전달하면서 

    Waitforsingleobject함수를 호출한다. 만약에 뮤텍스가 획득 가능한 상태라면 signaled상태에 있을 것이고(종료되었으니까) 때문에 뮤텍스를 획득하면서임계영역에 진입하게 된다. 

    * 추가 설명 : waitforsingleobject함수는 커널 오브젝트가 signaled 상태가 되어 반환할 경우 해당 커널 오브젝트의 상태를 non - signaled상태로 변경하므로 다른 쓰레드들은 임께 영역으로의 진입이 제한된다.


    세마포어

    : 뮤텍스와 유사하다. 그런데 차이가 있는데 그것은 카운트이다. 카운트란..

    임계영역에 접근 가능한 쓰레드의 개수를 조절하는 기능이다. 

    이름있는 뮤텍스 

    이벤트 **진짜 실행순서가 중요하다면 이걸해야하는데..


    위는 유저모드 아래는 커널모드임

    커널모드는 유저모드에 비해서 느리긴함..



    이벤트 동기화 넘기고

    쓰레드 풀링 넘기고



    메모리~~

    레지스터에서 데이터를 찾는데..캐쉬에 있으면 캐쉬히트, 없으면 캐쉬미스

    근데 데이터의 이동은 블록단위로 진행이 된다..블록 단위로 전송을 해서 스페이셜 로컬리티의 특성을 성능향상에 십분활용함

    * 스페이셜 로콜리티란 : 프로그램 실행시 접근하는 메모리 영역으 ㄴ이니 접근이 이루어진 영역의 근처일 확률이 높다는 프로그램의 성격이다.



    가상메모리?

    물리 메모리인 ram 이 부족할때 하드디스크가 많이 느리긴 하지만 여유 공간이 상당하니 그쪽에 주소를 옮겨보자는것..

    페이징 기법을 쓰는데..


Designed by Tistory.