본문 바로가기
임베디드 개발/임베디드 리눅스

LDD ] 시간 지연 함수 사용 시 주의점 (sleep vs delay)

by eteo 2026. 1. 20.
반응형

 

 

커널 공간(Kernel space) 시간 지연 함수

리눅스 커널에서 사용 가능한 시간 지연 함수는 CPU 점유 여부에 따라 sleep 계열과 delay 계열로 나뉜다.

 

 

 

 

1. sleep 계열 함수

sleep 계열 함수는 현재 실행 흐름을 중단하고 스케줄러에게 CPU 제어권을 반납하여 다른 태스크가 실행되도록 하는 방식이다. 지정한 지연 시간 이후에 스케줄링에 따라 다시 실행된다.

 

#include <linux/delay.h>

msleep(unsigned int msecs)
msleep_interruptible(unsigned int msecs) // 대기 중 SIGINT, SIGKILL 같은 시그널이 오면 즉시 깨어남
usleep_range(unsigned long min, unsigned long max);

 

 

 

sleep 계열 함수 사용 시 주의점

  • Atomic Context에서 호출 절대 금지
    • 인터럽트 핸들러(ISR) 내부나 스핀락(Spinlock)을 보유한 상태처럼 스케줄링이 허용되지 않고 선점 제한이 걸린 코드 구간에서 sleep 계열 함수를 호출하면, 시스템이 멈출 수 있다. 이런 Atomic Context에서 시간 지연이 꼭 필요하면 sleep 계열이 아닌 delay 계열 함수를 써야 한다.
  • 설정한 시간 보다는 더 늦게 깨어남
    • CPU를 양보한 후 설정된 시간이 지나면 실행 대기 상태가 되며, 이후 스케줄러의 선택에 따라 실제 재개 시점이 더 늦어질 수 있다.
  • 컨텍스트 스위칭 오버헤드를 고려해 짧은 지연에는 사용 비추
    • 태스크의 상태를 저장하고 복원하는 컨텍스트 스위칭 과정 자체가 CPU 자원을 소모하기 때문에, 수십 us 미만 짧은 지연에는 sleep 계열보다 delay 계열 함수를 사용하는게 훨씬 효율적이다.

 

 

선점과 선점 제한이란?

선점은 프리엠션으로 발음한다.

  • 선점(preemption) : 현재 실행 중인 태스크를 중단시키고, 더 적합한 태스크로 CPU 실행권을 넘기는 것
  • 선점 제한(preemption disabled) : 지금 실행 중인 코드가 끝날 때까지 스케줄러가 현재 태스크를 교체하지 못하도록 막아둔 상태

 

 

 

 

 

 

2. delay 계열 함수

delay 계열 함수는 지연 시간 동안 CPU가 루프를 돌며 시간을 때우는 Busy-wait 방식이다.

 

#include <linux/delay.h>

ndelay(ns)
udelay(us)
mdelay(ms)

 

 

 

delay 계열 함수 사용 시 주의점

  • 긴 지연 시간에는 사용 비추
    • 지연 시간 동안 해당 CPU 코어를 100% 점유하는 방식이다 보니 수 ms 이상 긴 지연에 사용하면 그 동안 다른 태스크가 실행되지 못해 시스템 전체의 응답성이 떨어질 수 있다. 
  • 설정한 시간 보다 더 빨리 깨어날 수도 있음 (Early Return)
    • delay 계열 함수는 CPU 클럭에 의존한 루프 기반 방식으로 지연을 수행하므로, DVFS(Dynamic Voltage Frequency Scaling)와 같은 전력 관리 기술로 CPU 클럭이 실시간으로 변하는 환경에서는 의도한 지연 시간보다 더 빠르게 반환될 수 있다.

 

 

 

 

 

 

 

vs 사용자 공간(User space) 시간 지연 함수

위에서는 커널 공간의 시간 지연 함수에 대해 알아봤는데 사용자 공간의 시간 지연 함수는 어떤 특징을 가질까?

 

리눅스 사용자 공간 표준 라이브러리인 glibc에는 sleep 계열 함수만 제공되고, Busy-wait 방식의 delay 계열 함수는 공식적으로 존재하지 않는다. 만약 필요하다면 개발자가 for 루프를 돌려 구현할 수는 있지만 권장되는 방식은 아니다.

 

그리고 커널에서 sleep 계열 함수를 잘못 쓰면 시스템 전체가 멈추는 대참사가 나지만, 사용자 공간과 같은 멀티 프로세스 환경에서는 해당 프로세스 하나만 잠들 뿐 스케줄러가 다른 앱을 강제로 실행시키므로 시스템 전체가 죽는 일은 없다.

 

사용자 공간에서 쓸 수 있는 대표적인 시간 지연 함수에는 다음과 같은 것들이 있다.

 

#include <unistd.h>

sleep(unsigned int seconds)
usleep(useconds_t usec) // POSIX에서 deprecated


#include <time.h>

nanosleep(const struct timespec *req, struct timespec *rem)

 

 

 

 

 
 
반응형