프로세스란 프로그램을 실행시키기 위해 메모리 공간을 할당받은 작업의 단위
프로세스는 코드, 데이터, 스택, 힙으로 구성되는 독립된 메모리 영역을 할당받음
스레드란 프로세스의 실행 단위로, 하나의 프로세스는 여러 개의 스레드를 가질 수 있고 각 스레드는 프로세스의 메모리 영역을 공유함
→ 코드, 데이터, 힙 영역을 공유하며 스택 영역만 따로 할당받음
→ 따라서 한 스레드가 자원을 변경하면 다른 스레드에도 변경 결과가 공유됨
멀티 프로세스 또는 멀티 스레드 환경에서 인터럽트나 시스템 콜 등에 의해 CPU가 할당 중인 작업을 다른 작업으로 변경할 때 발생한다. CPU는 작업하고 있던 프로세스의 상태나 프로그램 카운터 등의 작업 문맥을 PCB에 저장해놓고, 다음 프로세스의 PCB로부터 작업 문맥 정보를 읽어와서 이전에 실행했던 부분부터 다시 실행한다. 멀티 스레드 환경의 경우 멀티 프로세스 환경보다 컨택스트 스위칭에 들어가는 비용이 적게 드는데, 그 이유는 각각의 독립된 메모리 공간을 가지는 프로세스와 달리 스레드는 프로세스 내의 스택을 제외한 메모리 영역을 공유하기 때문에 문맥 교환 시 CPU가 스택 부분만 비우면 되기 때문이다.
파이썬은 **GIL(Global Interpreter Lock)**이라는 뮤텍스를 통해 기본적으로 싱글 스레드로 동작하도록 제한함으로써 동기화 문제를 회피한다. GIL이란 파이썬 인터프리터를 한 번에 하나의 스레드에 의해서만 실행 가능하도록 제한하는 것으로, 파이썬의 대중적인 구현체인 Cpython의 메모리 관리 기법이 Thread-safe 하지 않은 문제를 해결하고자 한다.
파이썬에서 모든 것은 객체로 취급되며, 각 객체는 참조 횟수(Reference Count)를 통해 관리된다. 파이썬의 메모리 관리는 가비지 컬렉션이 참조 횟수가 0인 객체를 메모리에서 삭제하는 방식으로 수행되는데, 이때 여러 개의 스레드가 하나의 객체에 접근해서 값을 변경할 경우 각 객체의 참조 횟수가 올바르게 관리되지 못할 수 있기 때문에 Tread-safe하지 않다. 그래서 이런 상황을 방지하기 위해 각각의 객체에 대한 상호 배제 기법이 필요한데, 모든 것이 객체로 취급되는 파이썬의 특성 상 일일이 락을 걸어 관리하기가 굉장히 까다롭다. 그래서 파이썬은 GIL을 통해 객체 단위가 아니라 스레드 단위로 락을 걸어 자원이 관리되도록 만들었고, 그 결과 싱글 스레드로 동작하게끔 제한되었다.
운영체제는 시스템 자원을 보호하기 위해 **이중 연산 모드(Dual-mode Operation)**를 지원한다. 이중 연산 모드란 CPU가 운영체제의 코드를 수행하는 커널 모드와 사용자 시스템의 작업을 수행하는 사용자 모드를 구분하고 각 모드를 0 또는 1의 값을 가지는 모드 비트(Mode bit)를 통해 구분함으로써 사용자 프로그램이 접근할 수 있는 자원에 제한을 두는 것이다. 이 때, 사용자 모드에서 제한없이 접근 가능한 자원에 대한 명령을 일반 명령이라고 하고, 커널 모드에서만 접근할 수 있는 자원(I/O 장치 등)에 대한 명령을 특권 명령이라고 한다. 시스템 콜이란, 사용자 모드에서 I/O 장치 등에 접근할 필요가 있을 경우 특권 명령을 수행하기 위해 CPU에게 커널 모드로의 변경을 요청하는 **일종의 인터럽트(소프트웨어 인터럽트)**라고 할 수 있다.
동작과정