Conversation
|
추가 참고할 링크 커널 쓰레드는 OS의 커널 스케줄러가 따로 관리하고, 유저 쓰레드는 JVM 내부 스케줄러가 관리하는군요. OS 측면에서는 하나의 프로세스에 현재 어떤 쓰레드가 동작 중인지는 알 수 없네요. 다음에는 JVM의 내부 스케줄러의 동작원리에 대해 학습해보면 좋을 것 같습니다. |
| // Test.java | ||
| class Test { | ||
| public static void main(String[] args) throws InterruptedException { | ||
| BankAccount b = new BankAccount(); | ||
| Parent p = new Parent(b); | ||
| Child c = new Child(b); | ||
| p.start(); // start(): 쓰레드를 실행하는 메서드 | ||
| c.start(); | ||
| p.join(); // join(): 쓰레드가 끝나기를 기다리는 메서드 | ||
| c.join(); | ||
| System.out.println("balance = " + b.getBalance()); | ||
| } | ||
| } | ||
|
|
||
| // 계좌 | ||
| class BankAccount { | ||
| int balance; | ||
| void deposit(int amount) { | ||
| int temp = balance + amount; // 임계구역 코드 | ||
| System.out.print("+"); // 시간 지연 의도를 위한 코드 | ||
| balance = temp; | ||
| } | ||
| void withdraw(int amount) { | ||
| int temp = balance - amount; // 임계구역 코드 | ||
| System.out.print("-"); // 시간 지연 의도를 위한 코드 | ||
| balance = temp; | ||
| } | ||
| int getBalance() { | ||
| return balance; | ||
| } | ||
| } | ||
|
|
||
| // 입금 프로세스 | ||
| class Parent extends Thread { | ||
| BankAccount b; | ||
| Parent(BankAccount b) { | ||
| this.b = b; | ||
| } | ||
| public void run() { // run(): 쓰레드가 실제로 동작하는 부분(치환) | ||
| for (int i = 0; i < 100; i++) | ||
| b.deposit(1000); | ||
| } | ||
| } | ||
|
|
||
| // 출금 프로세스 | ||
| class Child extends Thread { | ||
| BankAccount b; | ||
| Child(BankAccount b) { | ||
| this.b = b; | ||
| } | ||
| public void run() { | ||
| for (int i = 0; i < 100; i++) | ||
| b.withdraw(1000); | ||
| } | ||
| } | ||
| ``` |
| balance = 1000000 | ||
| ``` | ||
| * 간단한 실험을 통해, 우리는 시간 지연이 주어질 때 여러 쓰레드가 하나의 공유 자원을 사용하는 프로그램은 망가진다는 사실을 알 수 있다. 출력되는 결과는 운영체제에서 쓰레드를 스위칭하는 패턴이 매번 다르므로 수행할 때마다 다르다. 이는 공통변수, 즉 계좌의 잔액(common variable)에 대한 동시 업데이트(concurrent update) 가 이루어지기 때문이다. Java와 같이 High-level 언어에서는 한 줄로 족하지만, assembly code로 번역될 때 여러 줄로 바뀌므로 중간에 스위칭이 발생할 수 있다. | ||
| * 이를 해결하기 위해서는, 공통변수에 해당하는 임계구역(critical section)을 설정해 임계구역 코드에 접근하는 쓰레드가 단 하나만 존재하도록 해야 한다. |
There was a problem hiding this comment.
Q1) 임계구역이란, 공용자원을 의미하는 건가요?
There was a problem hiding this comment.
| ### 예시: 최초 S 값은 1이고, 현재 해당 구역을 수행할 프로세스 A, B가 있다고 가정하자. | ||
| * 먼저 도착한 A가 P(S)를 실행하여 S를 0으로 만들고 임계구역에 들어감 | ||
| * 그 뒤에 도착한 B가 P(S)를 실행하지만 S가 0이므로 대기 상태 | ||
| * A가 임계구역 수행을 마치고 V(S)를 실행하면 S는 다시 1이 됨 | ||
| * B는 이제 P(S)에서 while문을 빠져나올 수 있고, 임계구역으로 들어가 수행함 | ||
| * Bank Account Problem을 Semaphore를 활용하여 해결하면 다음과 같다. 쓰레드 동기화를 통하여 임계구역 문제를 해결하였고, 이에 따라 +- 출력을 제외하고 balance 값이 0 출력된다. |
There was a problem hiding this comment.
Q2) 세마포어와 뮤텍스는 어떤 차이점이 있을까요?
위 예시만 보면, 뮤텍스를 이용하는 것과 비슷해보여요
There was a problem hiding this comment.
뮤텍스는 하나의 쓰레드나 프로세스가 소유할 수 있는 Key를 기반으로 하는 상호배제 방법이고,
세마포어는 일종의 signaling mechanism으로서 현재 임계자원에 접근하고자 하는 쓰레드나 프로세스가 몇 개인지를 보여주는 상호배제 방법이다. 링크
-
The mutex object allows all the processes to use the same resource but at a time, only one process is allowed to use the resource. Mutex uses the lock-based technique to handle the critical section problem. Whenever a process requests a resource from the system, then the system will create a mutex object with a unique name or ID. So, whenever the process wants to use that resource, then the process occupies a lock on the object. After locking, the process uses the resource and finally releases the mutex object. After that, other processes can create the mutex object in the same manner and use it.
-
Semaphore is an integer variable S, that is initialized with the number of resources present in the system and is used for process synchronization.
-
Mutex uses a locking mechanism i.e. if a process wants to use a resource then it locks the resource, uses it and then release it. But on the other hand, semaphore uses a signalling mechanism where wait() and signal() methods are used to show if a process is releasing a resource or taking a resource.
There was a problem hiding this comment.
정리하면 뮤텍스을 이용해서 공유자원에 접근제어를 하는 건, 하나의 프로세스만이 공유자원에 접근할 때 이고,
세마포어 같은 경우는, N:N 의 관계 예를 들면 하나의 공유자원에 여러개의 프로세스가 접근가능할 때 사용하는 방법..
으로 이해했는데 맞을까요?
| @@ -0,0 +1,85 @@ | |||
| # 사용자 수준 쓰레드 vs 커널 수준 쓰레드 | |||
|  | |||
| * 즉, 스레드의 스케줄링 및 동기화에 시스템콜(커널호출)이 필요 없기 때문에 오버헤드가 적다. | ||
| * 그리고 커널 레벨 스레드는 커널이 직접 스레드를 관리해주는 것이기 때문에 유저 스레드 1개당 커널 1개가 맡아준다. 따라서 하나의 프로세스에 여러 유저 스레드가 있어도 동시에 실행이 가능하다. | ||
| * 하지만 여기서 유저 레벨 스레드에 I/O를 이용하면 치명적인 단점이 존재한다. | ||
| * 유저 레벨 스레드를 이용하면 커널은 프로세스 내의 스레드 존재를 모르기 때문에 하나의 유저 레벨 스레드가 I/O를 하면 나머지 모든 스레드가 멈추게 된다. |
There was a problem hiding this comment.
유저 레벨 스레드를 이용하면 커널은 프로세스 내의 스레드 존재를 모르기 때문에 하나의 유저 레벨 스레드가 I/O를 하면 나머지 모든 스레드가 멈추게 된다.
Q4) 이 부분의 경우, 저는 JVM 상의 여러 스레드 중에 하나의 스레드에서 I/O 작업 중에 Block이 생겼다면 해당 스레드만 멈추는 것이 아닌, JVM 프로세스 자체가 멈추게 된다..라고 이해했는데 맞을까요?
There was a problem hiding this comment.
네 저도 그렇게 생각합니다. 하나의 유저 레벨 스레드가 I/O가 하면 다른 모든 스레드 및 프로세스가 멈추게 된다.
| ### 예시: 최초 S 값은 1이고, 현재 해당 구역을 수행할 프로세스 A, B가 있다고 가정하자. | ||
| * 먼저 도착한 A가 P(S)를 실행하여 S를 0으로 만들고 임계구역에 들어감 | ||
| * 그 뒤에 도착한 B가 P(S)를 실행하지만 S가 0이므로 대기 상태 | ||
| * A가 임계구역 수행을 마치고 V(S)를 실행하면 S는 다시 1이 됨 | ||
| * B는 이제 P(S)에서 while문을 빠져나올 수 있고, 임계구역으로 들어가 수행함 | ||
| * Bank Account Problem을 Semaphore를 활용하여 해결하면 다음과 같다. 쓰레드 동기화를 통하여 임계구역 문제를 해결하였고, 이에 따라 +- 출력을 제외하고 balance 값이 0 출력된다. |
There was a problem hiding this comment.
뮤텍스는 하나의 쓰레드나 프로세스가 소유할 수 있는 Key를 기반으로 하는 상호배제 방법이고,
세마포어는 일종의 signaling mechanism으로서 현재 임계자원에 접근하고자 하는 쓰레드나 프로세스가 몇 개인지를 보여주는 상호배제 방법이다. 링크
-
The mutex object allows all the processes to use the same resource but at a time, only one process is allowed to use the resource. Mutex uses the lock-based technique to handle the critical section problem. Whenever a process requests a resource from the system, then the system will create a mutex object with a unique name or ID. So, whenever the process wants to use that resource, then the process occupies a lock on the object. After locking, the process uses the resource and finally releases the mutex object. After that, other processes can create the mutex object in the same manner and use it.
-
Semaphore is an integer variable S, that is initialized with the number of resources present in the system and is used for process synchronization.
-
Mutex uses a locking mechanism i.e. if a process wants to use a resource then it locks the resource, uses it and then release it. But on the other hand, semaphore uses a signalling mechanism where wait() and signal() methods are used to show if a process is releasing a resource or taking a resource.
| @@ -0,0 +1,85 @@ | |||
| # 사용자 수준 쓰레드 vs 커널 수준 쓰레드 | |||
|  | |||
| * 즉, 스레드의 스케줄링 및 동기화에 시스템콜(커널호출)이 필요 없기 때문에 오버헤드가 적다. | ||
| * 그리고 커널 레벨 스레드는 커널이 직접 스레드를 관리해주는 것이기 때문에 유저 스레드 1개당 커널 1개가 맡아준다. 따라서 하나의 프로세스에 여러 유저 스레드가 있어도 동시에 실행이 가능하다. | ||
| * 하지만 여기서 유저 레벨 스레드에 I/O를 이용하면 치명적인 단점이 존재한다. | ||
| * 유저 레벨 스레드를 이용하면 커널은 프로세스 내의 스레드 존재를 모르기 때문에 하나의 유저 레벨 스레드가 I/O를 하면 나머지 모든 스레드가 멈추게 된다. |
There was a problem hiding this comment.
네 저도 그렇게 생각합니다. 하나의 유저 레벨 스레드가 I/O가 하면 다른 모든 스레드 및 프로세스가 멈추게 된다.

학습한 내용