준비상태에서 CPU를 기다리고 있는 프로세스들은 운영체제의 스케줄러에 의해 실행상태로 전환된다.
실행상태의 프로세스들은 점유시간이 지나면 준비 상태가되고, 입출력 요청이 있는경우에 대기상태로 전환되기도 한다.
이와같이 운영체제가 프로세스의 준비상태와 대기상태를 관리 할 때는 스케줄링Q라는 자료구조를 사 용한다.선입선출 형식의 자료구조이다.

<출처: 유노코딩>
대표적으로 준비 큐 와 대기 큐가 존재한다. 준비큐는 CPU를 이용하기위한 프로세스들이 줄을 스기 위해 존재하는 큐, 대기큐는 입출력장치를 이용하기 위해 대기상태에 있는 프로세스들이 줄을 스기 위해 존재하는 큐이다. 큐에는 프로세스들의 컨트롤 블록들이 줄을 스게 되고 운영체제는 이를 보고 먼저 이용할 것을 실행한다.
우선순위가 높은 것이 있을 경우 새치기를 허용한다.
< 스케줄링 알고리즘 시 고려사항들 >
부하가 최소화되어야 한다
컴퓨팅 자원을 효율적으로 사용해야 한다
균형잡힌 스케줄링을 해야 한다
대기 및 응답 시간이 너무 길어서는 안 된다
<알고리즘의 종류들>
선입선출(First In First Out)
최단 작업 우선(Shortest Job First)
라운드 로빈(Round Robin)
우선순위 스케줄링(Priority Scheduling)
준비큐에 삽입된 순서대로 프로세스들을 처리하는 가장 단순하고 직관적임. 먼저들어온 프로세스가 종료상태가 되어야만 다음 프로세스가 실행될 수 있음. 우선순위가 같다면 먼저 온 프로세스가 먼저, 실행시간이 짧든 길든 순서대로 처리해서 비효율적일 수 있음.
프로세스의 실행시간이 짧은 프로세스들을 먼저 우선적으로 실행해줌. 그러나 프로세스의 실행시간을 정확히 예측하는 것이 거의 불가능하여 현실적이지 않음.
선입선출 알고리즘에 타임슬라이스 라는 개념이 더해진 스케줄링 방식. 타임 슬라이스란 프로세스가 CPU를 사용할 수 있는 점유시간을 의미함. 정해진 타임슬라이스 만큼만 CPU를 점유하고 시간이 다 지나면, 컨텍스트 스위칭하는 방식임.
각 프로세스마다 우선순위를 부여해서 우선순위가 높은 프로세스 먼저 실행하는 방식. 우선순위만 고려할 경우 우선순위가 낮은 프로세스가 배제되어 버리는 '기아'상태에 빠질 수 있음.
프로세스는 독립적으로 실행되지만 필요 시 다른 프로세스와 데이터를 주고받으며 통신하는 경우도 있음, 이를 프로세스 간 통신(Inter-Process Communication, IPC)라고 함.
통신을 하려면, 통신의 각 주체가 만날 수 있는 일종의 창구(매개체)가 필요함, 프로세스 간 통신 에서도 마찬가지이다.
프로세스가 만들어지면 독립적인 구조로서 각각의 영역을 가지고, 자신에게 할당된 메모리영역외에는 접근이 불가능해서 프로세스 간 통신은 쉽지 않다.
메일슬롯 방식
메일슬롯 방식의 IPC는 데이터를 받기 위해서 프로세스가 우체통역할을 하는 객체를 마련하고 이를 통해 데이터를 주고받는 방식
데이터를 받고 싶은 프로세스B(Receiver)는 밖에 우체통을 하나 마련, 이 우체통이 데이터 매 개체 역할을 하고 주소를 할당받은 하나의 객체임
데이터를 보내고싶은 프로세스A(Sender)는 이 주소를 통해 데이터를 보낼 수 있음
서로 관련없는 프로세스간에 유용
파이프 방식
파이프 방식은 운영체제가 파이프 라는 것을 생성하여 그것으로 데이터를 주고받음.
파이프 방식의 IPC는 익명 파이프 또는 네임드 파이프를 이용해 데이터를 주고받는다.
익명 파이프는 서로 관계가 있는 프로세스간에 통신을 할 때 사용하는 단방향 파이프이고,
네임드 파이프는 프로세스 간에 양방향 통신을 할 때 사용하는 파이프이다.
익명파이프는 서로 관련있는 부모, 자식 프로세스 사이에 유용
# 부모 자식간의 프로세스간 통신
from multiprocessing import Process, Pipe
import os
def send(conn):
print(f'{os.getpid()}가 {os.getppid()}에게 데이터를 보낸다!')
conn.send("Hello parent!")
conn.close()
if __name__ == "__main__" :
parent, child = Pipe() #Pipe():생성자함수->튜플형태로 두개의 객체가 반환됨
P = Process(target=send, args=(child,)) # 자식이 보내므로 args는 child
P.start()
print("기존 프로세스 아이디:", os.getpid())
print(parent.recv()) # 부모는 받음 -> hello parent 출력은 여기서 나옴
P.join() # join():프로세스가 작업을 종료할때까지 기다림.
<실행결과>

<실습코드2- 더 간단하게 통신:파일을 이용한 통신>
# 파일을 이용한 데이터 통신, 두개의 프로세스가 하나의 파이을 번갈아 읽는 것.
from multiprocessing import Process
import os
import time
def writer() :
print(f'{os.getpid()}가 파일에 쓴다')
with open('13.txt','w') as f: # w가 만드는 기능이기 때문에 13.txt가 없어도 실행시 만들어짐
f.write("Hello~")
def reader() :
print(f'{os.getpid()}가 파일을 읽는다')
with open('13.txt','r') as f:
print(f.read())
if __name__ == "__main__" :
p1 = Process(target=writer)
p1.start()
time.sleep(2)
p2 = Process(target=reader)
p2.start()
p1.join()
p2.join()
<실행결과>
