ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [컴퓨터 밑바닥의 비밀] 2.7 블로킹과 논블로킹
    Study/컴퓨터 밑바닥의 비밀 2025. 3. 2. 16:11

    들어가기 전에

    • 동기, 비동기를 이야기할 때 항상 두 가지 대상을 언급한다.
    • 프로그래밍에서는 서로 상호 작용하는 모듈 두 개 또는 함수를 의미한다.

     

    1) 동기

    • A와 B 두 대상이 강하게 결합된 것을 의미함
    • 위와 같이 작업 A가 작업 B에 의존하는 경우 A와 B는 동기

     

    2) 비동기

    • A와 B가 강한 결합과 같은 제약 없이 각자 자신의 작업을 독립적으로 실행할 수 있는 경우 A와 B는 비동기

     

    더보기
    • 동기 방식
      • 정의
        • 작업이 순차적으로 실행되는 것
        • 한 작업이 시작되면 해당 작업이 완료될 때까지 다른 작업은 기다려야 한다.
      • 장점
        • 간단하고 직관적임
      • 단점
        • 작업의 완료를 기다려야 하므로 처리 성능에 영향을 줄 수 있음
        • 한 작업이 지연되면 다른 작업에도 영향을 줌
    • 비동기 방식
      • 정의
        • 작업이 독립적으로 실행되는 것
        • 작업의 완료 여부를 기다리지 않고 다른 작업을 실행할 수 있다.
      • 장점
        • 주로 디스크 읽기/쓰기, 네트워크 통신 등의 시간이 오래 소요되는 I/O 작업에 유용함
        • 작업의 완료를 기다리지 않고 다른 작업을 수행하므로 처리 성능을 향상시킬 수 있음
      • 단점
        • 예외 처리 어려움
          • 동기 방식에서는 try-catch로 예외를 잡을 수 있지만, 비동기 방식으로 작업이 병렬로 실행될 경우 특정 작업에서 발생한 예외 추적 어려움
          • 실행 순서가 보장되지 않으므로 예외 추적 어려움

     

     

    2.7.1 블로킹과 논블로킹

    • 프로그래밍에서 함수를 호출할 때 주로 사용
    • 함수 호출 --> 호출자 스레드를 블로킹 시키는지/안 시키는지가 기준
      • 블로킹 방식
        • 함수 A가 함수 B를 호출할 때, 함수 B를 호출함과 동시에 운영체제가 함수 A를 호출한 스레드나 프로세스를 일시 중지 시킨 경우 (함수 B에 호출 방식은 블로킹 방식)
      • 논블로킹 방식
        • 위와 반대의 경우

     

    ex)

    • 블로킹 호출 핵심은 함수를 호출한 스레드나 프로세스가 일시 중지되는 것

     

    2.7.2 블로킹의 핵심 문제: 입출력

    • 모든 함수 호출로 인해 호출자의 스레드나 프로세스가 운영 체제에 의해 일시 중지되는 것은 아님
    • 블로킹은 대부분 입출력과 관련이 있음

     

    • I/O 작업 소요 시간이 CPU 작업 소요 시간보다 훨씬 오래걸리기 때문에 스레드가 I/O 작업을 할 때 CPU 제어권을 다른 스레드에 넘겨 CPU가 다른 작업을 할 수 있도록 함
    • I/O 작업이 완료되면 다시 CPU 제어권을 넘겨받아 다음 작업을 이어갈 수 있도록 함
    • CPU 제어권을 상실했다가 되찾는 시간 동안 스레드는 블로킹되어 일시 중지됨

     

    2.7.3 논블로킹과 비동기 입출력

    • 호출자 스레드를 블로킹하지 않으면서 입출력 작업을 시작할 수 있는 방법은 없을까? --> 논블로킹 호출 사용

     

    예시) 네트워크 데이터 수신

    • 데이터를 수신하는 함수인 recv가 논블로킹이면, 이 함수를 호출할 때 운영체제는 호출자 스레드를 일시 중시 시키지 않고 recv 함수를 즉시 반환함
    • 이후 호출자 스레드는 자신의 작업을 계속 진행하고, 데이터 수신 작업은 커널이 처리함 (두 가지 작업은 병행 처리됨)
    • Q. 데이터를 수신했는지 어떻게 알 수 있을까?
      1. 논블로킹 방식의 recv 함수 외에 결과를 확인하는 함수 함께 제공 (해당 함수를 호출해 수신된 데이터가 있는지 확인)
      2. 데이터가 수신되면 스레드에 메시지나 신호 등을 전송하는 알림 작동 방식 사용
      3. recv 함수 호출할 때, 데이터 수신 처리를 담당하는 함수를 콜백 함수에 담아 매개변수로 전달 (이때 recv 함수가 콜백 함수를 지원해야 함)
    • 이러한 호출이 '논블로킹 호출'이며, 이런 유형의 입출력 작업을 비동기 입출력(asynchronous I/O)라고 함
      • I/O 작업 시작할 때 호출자 스레드가 블로킹되지 않고, 호출자 스레드의 작업과 I/O 작업이 독립적으로 동시에 처리되기 때문에 비동기 방식임

     

    2.7.5 동기와 블로킹

    • 프로그래밍 관점에서, 동기 호출은 반드시 블로킹이 아니지만 블로킹 호출은 모두 확실한 동기 호출이다.

     

    예시)

    int sum(int a, int b)
    {
        return a + b;
    }
    
    void funcA()
    {
        sum(1, 1);
    }
    • sum 함수에 대한 호출은 동기이지만, funcA 함수가 sum 함수를 호출했다고 해서 해당 스레드가 블로킹되지 않음 (동기 + 논블로킹)
    • 반면 어떤 함수가 블로킹 방식으로 호출된 경우 이는 반드시 동기 호출임
      • 호출자 스레드가 블로킹되어 작업이 순차적으로 실행됨

     

    2.7.6 비동기와 논블로킹

    • 논블로킹이더라도 전체적으로 반드시 비동기는 아니며, 이는 코드 구현 방식에 따라 달라진다.

     

    예시)

    void handler(void *buf)
    {
        // 수신된 네트워크 데이터를 처리한다.
        ...
    }
    
    while (true)
    {
        fd = accpet();
        recv(fd, buf, NON_BLOCKING_FLAG, handler); // 호출 후 바로 반환, 논블로킹
    }
    • recv 함수는 논블로킹 호출이므로, 네트워크 데이터를 처리해 주는 handler 함수를 recv 함수에 콜백으로 전달함
    • 위의 코드는 비동기이자 논블로킹
    void handler(void *buf)
    {
        // 수신된 네트워크 데이터를 처리한다.
        ...
    }
    
    while (true)
    {
        fd = accpet();
        recv(fd, buf, NON_BLOCKING_FLAG); // 호출 후 바로 반환, 논블로킹
        
        while (!check(fd))
        {
            // 순환 감지
            ...
        }
        
        handler(buf);
    }
    • recv 함수는 여전히 논블로킹으로 호출되지만, while 반복문에서 감지를 시도하여 데이터가 도착하기 전까지 handler 함수를 사용할 수 없음
    • 즉, recv 함수는 논블로킹이지만, 전체적인 관점에서 위 코드는 동기임

    댓글

Designed by Tistory.