* 멀티태스킹
App 중에서 현재 실행 중인 프로그램이 프로세스이다.
멀티태스킹이란 여러 프로세스를 동시에 돌아가면서 명령문을 실행하여
동시에 여러개의 App을 실행하는 것이다.
CPU의 속도가 빠르기 때문에 가능하며 실제로는 빠르게 순차적으로 실행하는 것이다.
어떤 방법으로 순서를 주어서 실행하는 것이 효과적일까 ?
Process Scheduling
Cpu sheduling
* CPU 스케쥴링
CPU 스케쥴링이란 ? 여러 프로세스를 돌아가면서 실행하는 알고리즘
① Round-Robin vs ② Priority Aging
① 일정한 단위로 시간을 쪼개서 프로세스를 순차적으로 실행
② 우선순위가 높은 프로세스를 먼저 실행
* context-switching
명령어 로드:
CPU는 주 메모리에서 실행 중인 APP의 명령어를 가져와야 합니다.
이 명령어는 주 메모리에서 캐시 메모리로 이동합니다.
일반적으로 CPU는 캐시 메모리의 여러 수준을 사용하여 데이터에 대한 액세스 속도를 높입니다.
명령어 해석:
CPU는 명령어를 해석하여 해당 연산을 결정합니다.
명령어에는 산술 연산(덧셈, 뺄셈 등), 논리 연산(AND, OR, NOT 등),
분기(조건에 따라 다른 명령어 실행) 등 다양한 유형이 있을 수 있습니다.
데이터 로드:
CPU는 필요한 데이터를 주 메모리에서 가져와야 합니다.
이 데이터는 주 메모리에서 캐시 메모리로 이동합니다. CPU는 캐시 메모리의 데이터 존재 여부를 확인하고,
데이터가 없으면 주 메모리로부터 데이터를 가져와 캐시 메모리에 저장합니다.
데이터 처리:
CPU는 명령어와 데이터를 기반으로 연산을 수행합니다. 데이터는 레지스터에 로드되어 연산에 사용됩니다.
CPU는 산술 논리 장치(ALU)를 사용하여 데이터를 처리하고, 결과를 다시 레지스터에 저장합니다.
결과 저장:
연산의 결과는 일반적으로 레지스터에 저장됩니다.
이 결과는 필요에 따라 다시 주 메모리로 이동되거나 다음 연산에 사용될 수 있습니다.
다음 명령어로 이동:
CPU는 다음 명령어를 가져와서 반복적으로 위의 단계를 실행합니다.
명령어의 흐름에 따라 분기가 발생할 수도 있습니다.
이와 같은 과정을 반복하면서 CPU는 APP의 명령어를 실행하고 데이터를 처리합니다.
레지스터는 CPU 내부의 임시 저장소로, 데이터를 저장하고 연산에 사용됩니다.
이를 통해 CPU는 데이터에 빠르게 액세스하여 연산을 수행하며, APP을 실행합니다.
* 멀티태스킹 프로그래밍
* Varagnt
설치
https://developer.hashicorp.com/vagrant/downloads?product_intent=vagrant
설치 후 폴더 경로로 들어가서 작업폴더 생성
vagrant cloud 페이지로 이동하여 ubuntu 설치 준비
https://app.vagrantup.com/boxes/search
필요한 정보를 확인하여 설치
cmd를 통해 명령어를 입력하여 활성화
* Concurrent 예제1 - 코드 동시 실행
// main() 메서드를 실행하는 기본 실행 흐름에서 새로운 실행 흐름으로 분기하고 싶다면,
// Thread 클래스를 정의할 때 분기해서 실행할 코드를 담으면 된다.
// 그러면 두 개의 실행 흐름이 서로 왔다 갔다 하면서 실행된다.
//
// ## 멀티태스킹(multi-tasking)
// - 한 개의 CPU가 여러 코드를 동시(?)에 실행하는 것.
// - 실제는 일정한 시간을 쪼개 이 코드와 저 코드를 왔다갔다 하면서 실행한다.
// - 그럼에도 불구하고 외부에서 봤을 때는 명령어가 동시에 실행되는 것 처럼 보인다.
// - 왜? CPU 속도 워낙 빠르기 때문이다.
//
// ## CPU의 실행 시간을 쪼개서 배분하는 정책 : CPU Scheculing 또는 프로세스 스케줄링
// - CPU의 실행 시간을 쪼개 코드를 실행하는 방법이다.
// 1) Round-Robin 방식
// - Windows OS에서 사용하는 방식
// - CPU 실행 시간을 일정하게 쪼개서 각 프로세스에 분배하는 방식
// 2) Priority 방식
// - Unix, Linux 에서 사용하는 방식
// - 우선 순위가 높은 프로세스에 더 많은 실행 시간을 배정하는 방식
// - 문제점:
// - 우선 순위가 낮은 프로그램인 경우 CPU 시간을 배정 받지 못하는 문제가 발생했다.
// - 그래서 몇 년이 지나도록 실행되지 않는 경우가 나타났다.
// - 해결책?
// - CPU 시간을 배정 받지 못할 때 마다
// 즉 다른 프로세스에 밀릴 대 마다 우선 순위를 높여서
// 언젠가는 실행되게 만들었다.
// - 이런 방식을 "에이징(aging) 기법"이라 부른다.
//
// ## 멀티 태스킹을 구현하는 방법
// 1) 멀티 프로세싱
// - 프로세스(실행 중인 프로그램)를 복제하여 분기한다.
// - 그리고 분기된 프로세스를 실행시켜서 작업을 동시에 진행하게 한다.
// - 장점:
// - 분기하기가 쉽다. fork() 호출.
// - 즉 구현(프로그래밍)하기가 쉽다.
// - 단점:
// - 프로세스를 그대로 복제하기 때문에
// 프로세스가 사용하는 메모리도 그대로 복제된다.
// - 메모리 낭비가 심하다.
// - 복제된 프로세스는 독립적이기 때문에
// 실행 종료할 때도 일일이 종료해야 한다.
//
// 2) 멀티 스레딩
// - 특정 코드만 분리하여 실행한다.
// - 따라서 프로세스가 사용하는 메모리를 공유한다.
// - 장점:
// - 프로세스의 힙 메모리를 공유하기 때문에 메모리 낭비가 적다.
// - 모든 스레드는 프로세스에 종속되기 때문에 프로세스를 종료하면
// 스레드도 자동 종료된다.
// - 단점:
// - 프로세스 복제 방식에 비해 코드 구현이 복잡하다.
//
// ## 컨텍스트 스위칭(context switching)
// - CPU의 실행 시간을 쪼개 이 코드 저 코드를 실행할 때 마다
// 실행 위치 및 정보(context)를 저장하고 로딩하는 과정이 필요하다.
// - 이 과정을 '컨텍스트 스위칭'이라 부른다.
//
// ## 스레드(thread)
// - '실'이라는 뜻을 갖고 있다.
// - 한 실행 흐름을 가리킨다.
// - 하나의 실은 끊기지 않은 하나의 실행 흐름을 의미한다.
//
// ## 스레드 생성
// - 새 실을 만든다는 것이다.
// - 즉 새 실행 흐름을 시작하겠다는 의미다.
// - CPU는 스레드를 프로세스와 마찬가지로 동일한 자격을 부여하여
// 스케줄링에 참여시킨다.
// - 즉 프로세스에 종속된 스레드라고 취급하여
// 한 프로세스에 부여된 실행 시간을 다시 쪼개 스레드에 나눠주는 방식이 아니다.
// - 그냥 단독적인 프로세스처럼 동일한 실행 시간을 부여한다.
//
* Concurrent 예제2 - 실행 중인 스레드 알아내기
프로세스나 스레드를 동등한 자격으로 대우한다.
즉, CPU 스케쥴링을 할 때 차별을 두지 않는다.
JVM Stack은 각 스레드 별로 존재하며
스레드가 메서드를 호출할 때마다 로컬 변수를 각자의 stack 영역에 생성한다.
JVM Stack은 데이터를 통해 Method Area와 Heap 에 공유되어 사용할 수 있다.
스레드는 os에서 실행하기때문에 os마다 스케쥴링이 달라질 우려가 있다.