결합하여 외부에서는 하나의 조작으로 보이는 조작의 집합을 의미한다.
그리고 이러한 기능을 하기 위해서는 2가지의 조건이 필요하다.
모든 조작이 완료할 때까지 어떤 프로세스도 변경을 알지 못하도록 '비가시적'이어야 하며
조작중에 어느 하나라도 실패한다면 조작 전체도 실패하고 시스템의 상태를 조작 이전 상태로 복구해야함.
그렇기 때문에 Atomic Operation을 실행 했을때는 성공(조작을 완료) , 실패(변화 없음) 둘 중 하나의 결과만 나와야 한다는 것이다.
이러한 Atomic Operation의 예는 다음과 같다.
여러 프로세스가 특정 메모리 공간을 공유한다고 가정했을때
첫번째 프로세스가 그 메모리의 값을 변화시킨 후, 값을 입력하려는 순간 제어권이 뺏긴다.
두번째 프로세스는 높은 우선순위로 제어권을 뺏었고, 값을 변경 후 제어권을 돌려준다.
제어권을 돌려받은 첫번째 프로세스는 값이 바뀐지도 모르고 변경된 값을 입력한다.
이러한 프로세스 처리 과정을 통해 첫번째 프로세스는 두번째 프로세스가 자신이 참고해야하는 값을 바꿨다는걸 '알지 못한다.'
즉 , 우리는 이러한 Atomic Operation을 알기 전까지 스레드가 '충돌'났다고 표현을 하였으며 , 이러한 충돌을 방지하기 위해 1주차 프로잭트에서 Lock , Semaphore를 써서 스레드의 Atomic Operation을 막아왔던 것이다.
레지스터들의 설명을 보자.
scratch register = 작업 처리 속도를 높이기 위해 CPU가 명령을 실행할 때 사용하는 일시적인 기억장치
한마디로 하면 레지스터에 저장된 함수의 계산 결과를 저장해놓는게 Rax 레지스터라는 것이다.
https://os.phil-opp.com/returning-from-exceptions/#testing-it-again
뭔가 기묘한 사이트를 발견했고, 아직까지는 간단하게 읽어보았다.
코드에서 rax 값이 없을때 핸들러를 작동시킴
결과를 rax에 반환함.
이 되는데, interrupt를 발동시키고, 발동된 interrupt의 값을 저장하는 것이 rax 레지스터라 봐도 무방하겠다.
간단하게 정리를 하자면 user stak 는 context switching , interrupt를 발생시킨 후 돌아올때 어떠한 상태였는지를 저장하는 용도로 사용이 되는 스택이다.
그렇기 때문에 user stack에 함수호출,반환,매개변수,지역변수 등 스택에 들어가는 정보를 저장하는 곳이다.
kernel stack
user stack과 반대되는 것이 kernel stack인데, 이 스택은 kernel로 진입할때 interrupt 실행되는 시점의 프로세서 context를 push해 관리를 한다. 이후 핸들러 처리를 한 다음에 같은 프로세스가 다시 선택된다면 pop을 해서 context를 복원하고, 다른 프로세스가 선택된다면 context를 놔두고 새롭게 선택된 프로세서의 context를 복원하여 새로운 프로세스가 동작되게끔 한다.
한가지 주의해야 할 점이 kernel stack은 각 프로세스마다 할당되는 것이며, 프로세스 집합 위에 커다란 kernel stack이 있고, 그 kernel stack에 의해 모든 프로세스가 관리된다고 이해하면 안된다.
다시한번 말하지만, 그림에서도 보이는 저 kernel은 kernel space일 뿐 , kernel stack은 각 process마다 하나씩 할당되어 있다.
길게 설명은 안하고 부족한 부분만 보충한다.
소켓 통신에서 다음과 같은 함수들도 file descriptor연산자 이다.
소켓