-
라이브락(Livelock)이란?Computer Science/OS 2024. 4. 4. 21:59반응형
1. 라이브락이란?
라이브락은 프로세스가 '진행 중' 상태이지만 실제로는 어떠한 유용한 작업도 수행하지 않는 상태를 말합니다. 이는 프로세스가 상호작용하는 방식 때문에 발생하며, 특정 조건을 만족시키기 위해 반복적으로 상태를 변경하지만, 결국은 원하는 결과를 달성하지 못하는 경우에 발생합니다. 데드락과 달리, 라이브락 상태의 프로세스는 실행 중인 상태를 유지하지만, 유용한 일을 하지 못합니다.
2. 라이브락 예시코드 구현에 앞서
라이브락을 명확히 보여주는 코드 예시는 데드락보다 구현하기 어렵습니다. 라이브락의 상황을 설명하기 위해, 두 개의 스레드(또는 고루틴)가 서로의 상태 변경을 지속적으로 감지하고, 그에 따라 자신의 상태를 변경하는 예를 들 수 있습니다. 이 과정에서 양쪽 모두 진행을 멈추지 않고 계속 상태를 변경하지만, 실제로는 어떤 유용한 작업도 완료하지 못합니다.
3. Java 예시: 서버 상태에 따른 두 스레드의 작업 조정
두 스레드가 서로 반대의 조건에서 작업을 수행하려고 하지만, 조건이 동시에 변하여 결국 둘 다 작업을 수행하지 못하는 상황을 구현합니다.
public class LiveLockExample { static class SharedResource { private boolean active = true; public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } } static class Worker { private String name; private boolean active; public Worker(String name, boolean active) { this.name = name; this.active = active; } public String getName() { return name; } public boolean isActive() { return active; } public void work(SharedResource sharedResource, Worker otherWorker) { while (active) { // Wait for the other worker to become inactive if (otherWorker.isActive()) { System.out.println(name + " is waiting for " + otherWorker.getName() + " to become inactive."); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } continue; } // If the shared resource is active, this worker becomes inactive and vice versa. if (sharedResource.isActive()) { System.out.println(name + " sets the shared resource to inactive."); sharedResource.setActive(false); } else { System.out.println(name + " activates the shared resource."); sharedResource.setActive(true); } // This worker becomes inactive and lets the other worker work. this.active = false; otherWorker.active = true; } } } public static void main(String[] args) { final SharedResource sharedResource = new SharedResource(); final Worker worker1 = new Worker("Worker 1", true); final Worker worker2 = new Worker("Worker 2", true); new Thread(() -> worker1.work(sharedResource, worker2)).start(); new Thread(() -> worker2.work(sharedResource, worker1)).start(); } }
예시에서 Worker 객체들은 서로 상대방이 작업을 완료하길 기다리는 동안, 상대방도 동일하게 기다리고 있어 어느 한 쪽도 실제 작업을 진행하지 못합니다. 서로의 상태를 바꿔가며 반복적으로 작업을 시도하지만, 결국 진전이 없는 상태가 됩니다.
4. Go 예시: 처리 요청 간의 종속성에 따른 고루틴의 라이브락
Go 예시에서는 채널을 통해 두 고루틴이 서로의 작업 완료를 기다리지만, 조건 변경으로 인해 실제 작업이 이루어지지 않는 상황을 구현합니다.
package main import ( "fmt" "time" ) func worker(workerName string, startWork chan bool, otherWorkerReady chan bool) { for { select { case <-startWork: fmt.Println(workerName, "is ready to work but waiting for the other worker.") // Signal that this worker is ready otherWorkerReady <- true case <-otherWorkerReady: fmt.Println(workerName, "notices the other worker is ready but decides to wait more.") // Decide to wait more, expecting the other worker to start work time.Sleep(100 * time.Millisecond) // Signal readiness again, causing a livelock startWork <- true } } } func main() { worker1Ready := make(chan bool) worker2Ready := make(chan bool) go worker("Worker 1", worker1Ready, worker2Ready) go worker("Worker 2", worker2Ready, worker1Ready) // Start the livelock cycle worker1Ready <- true select {} }
예시에서 두 고루틴은 채널을 통해 서로의 준비 상태를 알리지만, 결국 서로가 서로를 기다리는 상태에 빠지게 됩니다. 이는 고루틴들이 계속 실행되고 있지만, 실제로는 진행되는 작업이 없는 라이브락 상태를 나타냅니다.
라이브락 문제는 주로 복잡한 동기화 상황이나 의존성이 높은 작업 처리에서 발생할 수 있습니다. 해결 방법으로는 타임아웃, 상태 변경 시 무작위성 도입, 의존성 줄이기 등이 있습니다.
5. 추가 팁:
- 라이브락 감지 및 해결: 라이브락은 시스템의 모니터링 도구를 통해 감지할 수 있습니다. 일반적으로 라이브락을 해결하기 위해서는 프로세스나 스레드의 상태 변화 조건을 재설정하거나, 상태 변경 로직에 무작위성을 도입하여 연속적인 상태 변경이 반복되지 않도록 할 수 있습니다.
- 예방 전략: 라이브락을 예방하기 위해서는 프로세스 간의 의존성을 최소화하고, 가능하다면 각 프로세스가 독립적으로 완료할 수 있는 작업 단위를 정의해야 합니다. 또한, 시스템 설계 시 상태 변경 조건을 명확하게 정의하고, 예상치 못한 상호작용으로 인한 라이브락
반응형'Computer Science > OS' 카테고리의 다른 글
기아상태(Starvation)란? (0) 2024.04.06 메모리 구조(Memory Structure)란? (0) 2024.04.05 컴파일(Compile)과 런타임(Runtime)이란? (0) 2024.04.05 데드락(Deadlock)이란? (1) 2024.04.03 스레드 세이프(Thred Safe)란? (0) 2024.03.30