[yummyHitOS] 18 day (2017.08.04)
아닛 9일만에 포스팅하는 거라닛... 죄송해여ㅜㅠ 전 그래도 이제 4일된 줄 알았져...ㅠㅜㅠ시간 참 빠르네영!!
여러분!! 야미의 첫 개발 프로그램이자 아직 개발 진행중인 프로그램인 yummyKit도 포스팅을 시작했어여!! 박수쨖쨖~~ 그런데 yummyKit을 만든지 약 1년이 된 후 다시 보니 코드를 마니 바꿔야겠더라구여? 정녕 멍청하게 짜여진 소스들...
우리는 오늘 동기화에 대해 알아가기로 하였어요. 동기화라고 들어보신 적 있지않나여? 아이폰 사용자는 iTunes와 아이폰 동기화... 갑자기 백업되면서 막 컴퓨터 용량 잡아먹고... 사진이나 노래가 막 사라지는 프로불편러였던 적이 있었어여 헿헤헤헿
안드로이드를 사용중이신 분들은 구글 동기화가 있지여!? 구글 계정에 자신의 전화번호부, 메시지 등을 백업하고 나중에 휴대폰이 바뀌면 자동으로 복원하는 그런 편리한 시스템!!
넵 이 편리한지 불편한지 시스템을 우리가 오늘 진행한다는 것입니다 여러분!!
가카 저는 웃지 않았습니당...
참 포스팅과 개발을 병행하다보니 느낀건데.. 제가 설명드리는 것 외의 책 내용을 그대로 담아야 할까 싶은 고민이 생겨써여!! 저처럼 책을 이미 사신분이라면 물논 읽으시면 되겠지만, 혹여나 책이 없으신 분들을 위해 팁이랄까... 그런게 들어가야하나... 너무 책 위주로 깊이 파고드는 것이 아닌가.. 싶더라구여!!
그 부분은 책의 모든 챕터를 포스팅 한 후 할까여? 뭐가조을까여? 늉늉 선택장애... 최근에 부트로더를 다시 건드렸었거둔여 이 내용은 나중에 GUI모드에서 말씀드릴게여!!
Synchronization
동기화(Synchronization)는 컴퓨터 시스템(기능적 모듈간의 통신, 메모리와 CPU간의 데이터 전송), 네트워크, GPS등의 많은 부분에서 사용되어여. 우리는 소프트웨어적으로 구현하는 동기화이기 때문에, 동시에(정말 0.00000000000000001초도 오차없는 완전 동시!) 데이터베이스상의 데이터 일치를 의미하는 동기화가 알맞아여!!
예를 들어, 은행 서버에 접속하는 사용자를 생각해 볼 때, 사용자가 10만원을 출금하는 동시에 입금을 한다면 같은 계좌에 접근되기 때문에 출금 혹은 입금 둘 중 하나만 진행되겠지여!? 출금만 된다면 10만원 넣은 것이 처리되지 않았기 때문에 문제가 될 것이고, 입금만 된다면 이사람은 10만원을 공짜로 얻은 것이 되기 때문에 이 또한 문제가 되겠지여!! 이러한 동기화 문제 때문에 한 번에 접근하지 못하도록 만드는 방법이 생겨써여!
그러타면 한 계좌번호 혹은 이렇게 한 공통적인 부분에 접근하지 못하도록 하려면 어떻게 해야 할까요!? 뭔가 상상을 해보면 감이 오시지 않나여?!
현재 사용중인 것을 잠가버리기! 접근 못하게 막아버리기! 게임에서 동일 사용자로 로그인하면 로그인 안되는거 아시죠?! 그것처럼 하면 되지 않을까요!?
이렇게 동일한 공간을 '임계영역(Critical Section)' 이라고 불러요. 먼저 사용중인 자원이 있다면, 이 영역에 접근하려는 다른 자원은 먼저 사용중인 자원이 끝날 때까지 대기하게 되는데, 사용중인 자원이 잘못 되었거나 실제로는 사용중인 자원이 없는데 임계영역이 사용중이라고 잘못 표시해주면 큰 오류가 발생하게 되겠죠?
dead lock
이러한 오류는 '교착상태(Dead Lock)' 이라는 용어로 사용되는데, 서로 다른 두 자원이 동시에 접근할 때의 오류, 아무 자원도 임계영역을 사용하지 않는데 사용중이라는 플래그로 나타냈을 때 더이상 임계영역에 접근하지 못하게 되는 오류 등 임계영역에 오류가 발생할 때를 의미해요.
갑자기 이렇게 2가지 용어가 튀어나와서 놀라셨나여?! 임계영역과 교착상태는 Thread의 가장 중요한 부분이거든여!! 쓰레드를 사용하실 때 어떻게 해야 교착상태를 피할지, 어떻게 해야 쓰레드가 효율적으로 작동할지 많은 고민을 하시고 구현해주셔야 해요!! 이것이 저의 첫 코딩에서 가장 큰 난관이었단 말이예여 T^T
그렇다면 이제 동기화에 대해 다 설명했을까여!? 아니요~!! 아직 발을 딛지도 않았어여!! 개념설명은 위키백갓이 다 해줄테니 상관없지만, 우리는 더 깊이 공부할 개성파잖아여!!! 여태 설명은 컴공이라면 그냥~ 기본적으로 해야된다~ 싶을정도로 T^T(그냥 한거야~ 김구라님과 신정환님의 넘나 웃긴 콩트가 생각나네여!! 전 신정환님 좋아했는데 ㅜㅜㅠ 얼른 복귀하시길 바래여!! 그런 의미에서 짤투척..)
하관 내놓고!! 그냥~한거야~ 그냥 한거라니깐~
그럼 뭐가 더있나여 야미님!! 임계영역을 공부하면 임계영역을 구현하기 위해 사용되는 스핀 락(Spin Lock), 뮤텍스(Mutex), 세마포어(Semaphore), 크리티컬섹션(Critical Section) 용어와 사용 법을 알고 가야해요!! 전 암것도 모르고 막 비쥬얼스튜디오에는 WaitForSingleObject()라는 함수 쓰기만 했었는데... 지금 그 코드를 보면 참으로 한심하지 아니할 슈가 없더라구여 ㅜㅠ
spin lock
스핀 락(Spin Lock)이란 교착상태를 방지하기 위해 사용하는 기법으로 현재 임계영역이 사용중이면 임계영역이 비워질 때까지 대기하는(Spin!! Round and Round!! 계속 돌겠다는 의미잖아여!! 그래서 스핀인가바여!) 방식이예요. 커널에서 Context Switching을 통해 부하를 주지말고 그냥 Loop를 돌며 기다려보자~ 라는 의미에서 만들어졌다고 해요. 스핀 락 상태인 자원은 바쁜 대기상태에 들어오고, 이것은 다른 CPU에게 점유율을 양보하지 않고 내가 먼저다!! 라는 높은 우선순위의 이기적인 상태에 들어가게 되지요! 이러한 이유 때문에 스핀 락은 멀티 쓰레딩, 멀티 프로세서에서 유용해요.
저는 처음 뮤텍스라는 이름 보았을 때, 두 가지가 생각나써여. 하나는 라텍스...(학창시절 천장을 이루고 축구공을 차면 천장을 깨트렸던 그 천장의 물질인 라텍스...)와 다른 하나는 뮤턴트...(블리자드 회사의 Frozen Throne이라는 유즈맵용 게임에서 Chaos로 불린 게임의 언데드 영웅 중 하나예여!! 키작은 좀비였어요!!) 넵... 제가 그만큼 공부는 안하고 이런거밖에 몰랐습니다 ㅜㅠㅜ
mutex
뮤텍스(Mutex)란 커널에서 사용되는 임계영역 접근 방법이예여. 여러 프로세스의 쓰레드 사이에서도 동기화가 가능할만큼 아주아주 중요하고 유용한 녀석이져!!
그림과 예제로 살펴볼게여!!
좌측은 MSDN(MicroSoft Development Network)라고 쓰고 윈도우 혹은 마쏘라고 부르는 곳에서 알려주는 mutex예요. 친절히 번호도 적어주시고, 어떤 함수가 있는지(InitializeMutx() 함수와 WaitForSingleObject()함수, ReleaseMutex()함수가 보이네여!)도 친절히 설명해주셔서 감사하지만 전 리눅스의 pthread를 좋아해서여... 그런데 윈도우 설명만큼 이쁘게 설명해주신 pthread가 없길래 우측의 사진을 가져옴과 동시에 코딩을 간단히 진행해보아써여!!
cat 명령을 통해 저의 mutex_test.c 파일을 보여드려써여! 먼저 main함수를 살펴보면, pthread_mutex_init()함수를 통해 mutex를 초기화 시키고(MSDN에서의 InitializeMutex()와 상응하겠져!?) 이 후 pthread_create()를 통해 thread를 생성시켜 주었어요(이는 MSDN에서 CreateThread()와 가장 가까울 것 같네여! _beginthreadex()는 다루기 어려웠던 야미...)
이 후의 pthread_join()함수는 쓰레드 종료를 기다리는 거랍니다!! 만약 tid[1]에 해당하는 쓰레드가 끝났을 지언정, pthread_join(tid[1], NULL)에는 접근하지 못해여!! tid[0]이 끝나야만 pthread_join(tid[0], NULL) 함수가 "빨래 끝~~ tid[0] 끝~~" 이란 마음으로 다음 명령줄을 수행한답니다!!
그렇다면 trythis() 함수를 살펴볼까여? 여기서 Mutex를 사용해주네여!! 이 함수는 생성되면서 동시에 먼저 뮤텍스를 잠가서 다른 자원이 사용할 수 없도록 막아줘요. 이 후 trythis() 함수를 수행한 후 뮤텍스를 해제하여 다른 자원이 접근할 수 있도록 해주네요!
굳이 뮤텍스를 쓸 필요없이 그냥 trythis()함수를 thread로 돌리면 안되냐구여? 그러면 두 쓰레드가 함께 들어와서 프로세스가 꼬여여!! 0xFFFFFFFF가 전부 반복될 때까지 각 쓰레드가 빙글빙글 돌텐데, 중간에 충돌이 일어나면 이보다 더 큰 코드는 겉잡을 수 없을 만큼의 오류를 범하게 될테니까여!! 물논 아주아주 예제스러울 뿐, 당장엔 실제로 필요한 것인가 싶지만, 점차 우리의 OS에서 아주 많은 Mutex를 사용할 것이기에 완벽히 이해하시는 것이 좋을 것 같아여!!
참, 참고로 리눅스에서 사용되어지는 쓰레드인 pthread 라이브러리를 사용하시기 위해선 야미처럼 gcc 명령의 옵션에 -lpthread를 꼭 넣어주셔야해요! -l 옵션은 library를 의미한답니다!
semaphore
다음으로는 세마포어(Semaphore)인데, 세마포어는 뮤텍스와 비슷해요. 뮤텍스처럼 커널에서 사용되는 임계영역 접근 방법인데 세마포어는 접근 가능 쓰레드의 개수를 정할 수가 있어여!! 뮤텍스는 무조건 한 쓰레드만 접근 가능하고 그 이후 쓰레드(자원이라 했다가 쓰레드라 했다가 넘나 정신없어서 죄송해여...)가 접근하면 대기하게 해주지만, 세마포어는 한 쓰레드가 접근해도 세마포어에 설정된 개수만큼까지 임계영역에 들어올 수 있게 해줘요! 그 숫자를 넘어가면 막아버리구요.
세마포어의 제한 쓰레드 수를 1로 하면 뮤텍스랑 같게되는거 아닐까여? 맞아여!! 아주 예리하시네여!! 레드벨벳 예리세여? 죄송...
이제 남은 것은 크리티컬섹션!! 그런데 아까 임계영역 용어 설명할 때 옆에 Critical Section이라고 적지 않았나여?! 오오 오늘따라 예리하신 것이 넘나 행보카네여 :D
critical section
크리티컬섹션(Critical Section)이란 임계영역을 대표하는 용어로 커널 영역이 아닌 유저 영역에서 사용되는 임계영역 접근 방법의 일종이예요. 한 프로세스의 쓰레드 사이에서만 사용이 가능하기 때문에, 뮤텍스보다 유용하진 못할지언정 사용이 조금 더 편리한 점이 있죠! 어플리케이션 혹은 프로그램을 만들 때는 유저영역에서 프로세스를 수행하기 때문에 크리티컬섹션을 이용하는 것이 오류를 줄이고 안정감 있도록 만들 수 있어요!!
드디어 우리 동기화에 대한 기초 지식이 끝나써여!! 그런데 18일차쯤 되니까 약간 불안감이 몰려오네영... 항상 초반에 이렇게 불태워 설명하면 이후에 설명할 것이 없어지는 듯한 느낌적인 느낌~~ 이 느낌때문에 제가 책의 내용도 적어야하나 싶었나바여ㅜㅠ
책을 몇 페이지 넘기니 경쟁상태와 상호배제라는 용어가 보이네여!! 임계영역과 나란히 있는 친구들인데 임계영역에 대해서만 설명을 하면 이 친구들이 서운하겠져?!
race condition
경쟁상태(Race Condition)란 장치 혹은 시스템, 우리에게 있어서는 태스크나 쓰레드, 프로세스 등이 두 개 이상의 동작을 동시에 수행하려고 할 때 발생하는 안좋은 상태예요. 안좋은 상태라 함은 데드락과 같은 위험성이 있다는 의미이구요. 왜 위험한지 잘 모르시겠다구여?! 데이터 읽고 쓰기의 상황으로 예를 들자면, 여러 태스크가 접근했을 때 데이터가 덮어쓰기 되거나 잘못 쓰여진 데이터를 읽는 작업이 이루어지면 에러가 발생하게 되겠죠!? 그렇기에 메모리적으로 위험성이 있구여!
이 한 프로그램 때문에 여러 프로그램이 피해를 보는 상황이 와서 블루스크린이 빠밤!! 하고 뜨면 어떡해여!!
끼욝.. 넘나 보기 싫은 것... 컴퓨터 공부를 미리 했으면 아... 저게 주소값이구나... 저기서 뭔가 문제구나... 했을텐데ㅜㅠㅜ 어릴때 게임이나 주구장창했으니 저런걸 알리가 없었져ㅜㅠ 그냥 놀래서 본체 파워를 꾸욱 눌렀을 뿐이네영 ㅜㅠ
또한 경쟁상태는 Network에서도 쓰이는 용어예요! 둘 이상의 사용자가 동시에 가용한 채널을 이용하려고 시도할 때 두 컴퓨터 모두 채널이 현재 사용 중이라는 통보를 받지 못했을 경우 네트워크에서 정한 정책에 따라 알파벳 순서라거나, 어떠한 정책에 의해 한 사용자를 받아들였다고 하면 그 사용자가 옳지 못한 사용자일 가능성도 있기 때문에 해킹의 위험성도 있게 되겠죠?!
물논 오류는 당연하구여! 테이블이 꼬일 위험도 있겠고, 장비를 바꿔야 하는 불상사도 일어날 수 있겠네여... 어우 그켬이예여...
상호 배제(Mutual Exclusion)란 용어를 보시면 뭔가 보이시지 않나여?! Mut...Ex... 넵!! 뮤텍스여 뮤텍스!!! 임계영역에서 뮤텍스란 것의 설명을 아주 대~충하고 간 것 같았는데, 이러케 상호 배제와 함께 다시 나타나주네여!! 공용 자원이 담겨있는 임계영역의 동시 사용을 피하게 해주는 방식이 뮤텍스이자 상호배제예요!
20장 2절 3번째 설명에서도 뮤텍스와 세마포어의 차이점에 대해 설명이 되어있네여! 그것도 모르고 씬나가지고 주절주절댔던 제가 넘나 창피하네여ㅜㅠ 역시 갓승훈 선생님의 책은 조금도 모자란 구석이 없어여..(1일 1칭찬)
책에서 설명되었지만 부연설명이랄까... 아니면 좀 더 간략히 설명한달까... volatile에 대해 짚어보고 이번 포스팅을 마칠게여!(아닛 뭐 동기화 쪼꼼 설명하고 끝내나여 야미님? 아녜여ㅜㅠ 이 전 포스팅에서 말씀드린 것처럼 정말 이번 챕터와 이전 챕터에서는 설명할 것이 너무 없더라구여... 늉늉 ㅜㅜ)
Volatile
volatile은 자료형과 조금 다르게 static같이 자료형 앞에 붙는 녀석이예요! C언어에서는 Memory Map Input/Output(메모리 맵 입출력, MMIO)을 제어할 때 사용되어진답니다! 우리가 일반적으로 선언했던 전역변수 혹은 지역변수는 컴파일러가 컴파일 할 때 메모리 접근을 최소화 하고 불필요한 접근을 줄여 성능 향상을 하기 위해 코드 최적화 작업을 거치는데, volatile이 붙은 변수에 대해서는 이런 작업을 거치지 않아요.
이렇게나 간단한 코드를 보아요! #####으로 위 아래를 구분시켜두었는데, 먼저 위 volatile을 사용하지 않은 코드는 그냥 바로 무한루프상태에 빠져서 건드릴 수 없게 되겠져?
과연 그러타면 아래 volatile을 사용한 코드는 어떨까여?! 똑같이 무한루프에 빠질 것만 같이 생겼지만, 이 코드는 메모리에 직접 접근하기 때문에 외부에서 이 변수의 값을 조정하면 루프를 탈출 할 수 있다는 점이예여!! 그 외부가 하드웨어든, 소프트웨어든 어느 방법이든간에 일반적인 무한 루프로 인한 멈춤이 아니라는 것이져!!
역시 코드로 봐야 이해가 쏙쏙! 되지 않나여?! 아니라구여? 저만그래여? 에이~ 코드로 보는게 솔직히 이해 더 잘되시자나여~! 죄송해여... 한 번 익살 떨어 봤어여...ㅠㅜㅠ쭈굴...
이제 구현내용을 보여드릴 때가 된 것 같아여!! 22장까지 한 후 11장부터 22장까지 진행된 구현을 보여드려야 할 것 같네여!! 혹씨 윈도우에서 에러나는 부분이 없겠져..? 여러분도 우분투로 얼른 갈아타셨으면... 헿헤~
동기화부분은 우리처럼 OS 개발하는 사람 뿐 아니라 일반 개발자들도 깊이 이해하셔야하는 부분이예여!! 쓰레드를 어떻게 사용하느냐에 따라 오류를 내지 않거나 메모리 사용량이 달라지는 부분이니까여!!
이제 나머지 코드 구현을 하시면 허무한 뮤텍스 테스트만 쪼꼼 나와여! 하지만 이거슨 며칠 후의 우리를 환상의 나라로 초대하는 시작단계이니 너무 허무해하지 마시구 더 열심히 해보아여!! 아쟈아쟈!!
그럼 정진운님의 춤신춤왕 Second 짤과 함께 다음 챕터에서 뵈어여!!! 오늘도 고생 많으셨숩니당~~!!
Check out the yummyhit’s website for more info on who am i. If you have questions, you can ask them on E-mail.
댓글남기기