Summary: 동기/비동기는 작업의 완료를 어떤 구조로 처리하는가에 대한 개념이고, 블로킹/논블로킹은 호출한 흐름이 멈추는지 여부에 대한 개념이다. 두 축은 서로 독립적이며, 결합되면 네 가지 조합으로 나타난다. 이 글은 각 개념의 정의·장단점·사용처와 Verilog 예제, 그리고 네 가지 조합을 정리한다.
동기란?

동기는 하나의 작업이 완료될 때까지 다른 작업을 대기시키는 방식이다. 현재 작업이 끝나야 다음 작업이 시작되므로 실행은 순차적으로 진행된다.
이 순차성은 장점과 단점을 동시에 만든다. 실행 순서가 명확하므로 구조를 이해하기 쉽고 디버깅도 비교적 수월하다. 반면 앞 작업이 오래 걸리면 뒤 작업도 함께 대기해야 하므로, 특정 작업의 지연이 전체 응답성 저하로 직결된다. 구조의 단순함과 지연 전파는 모두 순차적 실행이라는 하나의 성질에서 비롯된다.
주로 데이터베이스 트랜잭션, 파일 읽기/쓰기, 연속적인 계산 작업 등에 사용된다.
요약하자면 아래와 같다.
| 항목 | 설명 |
| 실행 방식 | 앞 작업이 끝나야 다음 작업 실행 |
| 흐름 | 순차적 |
| 장점 | 구조가 단순하고 이해하기 쉬움 |
| 단점 | 오래 걸리는 작업이 있으면 전체 흐름이 멈출 수 있음 |
| 사용 예 | 파일 읽기/쓰기, 데이터베이스 트랜잭션, 순차 계산, 일반 함수 호출 |
비동기란?

비동기는 하나의 작업이 완료되지 않아도 다른 작업을 동시에 진행하는 방식이다. 각 작업이 독립적으로 수행되며 병렬적으로 실행될 수 있다.
비동기의 이점은 시스템 자원을 효율적으로 사용하고 응답 시간을 단축할 수 있다는 점이다. 대신 실행 순서와 완료 순서가 일치하지 않을 수 있다. 동기에서 성립하던 "요청 순서와 완료 순서의 일치"가 비동기에서는 보장되지 않으며, 이 점이 흐름 추적과 디버깅을 어렵게 만든다.
네트워크, 이벤트 기반 프로그래밍 등에 사용되며, 임베디드 환경에서는 비동기 처리가 자주 사용된다.
요약하자면 아래와 같다.
| 항목 | 설명 |
| 실행 방식 | 작업 완료를 기다리지 않고 다음 작업 진행 |
| 흐름 | 완료 순서가 요청 순서와 다를 수 있음 |
| 장점 | 응답성 향상, 자원 활용 효율 증가 |
| 단점 | 코드 흐름이 복잡해질 수 있음 |
| 사용 예 | 네트워크 요청, 이벤트 기반 프로그래밍, 인터럽트, DMA, 타이머 |
동기와 비동기의 차이
두 방식의 차이는 결국 "다음 작업을 언제 시작하는가"와 "완료 순서가 요청 순서와 일치하는가"로 요약된다. 동기는 작업 완료 후에 다음 작업을 진행하고 완료 순서가 요청 순서와 대체로 같지만, 비동기는 완료를 기다리지 않고 다음 작업을 진행하므로 실행 흐름이 비순차적일 수 있고 완료 순서도 요청 순서와 달라질 수 있다.
| 구분 | 동기 | 비동기 |
| 작업 진행 방식 | 작업 완료 후 다음 작업 진행 | 작업 완료를 기다리지 않고 다음 작업 진행 |
| 실행 흐름 | 순차적 | 비순차적일 수 있음 |
| 완료 순서 | 요청 순서와 대체로 같음 | 요청 순서와 다를 수 있음 |
| 장점 | 이해하기 쉽고 디버깅이 쉬움 | 응답성이 좋고 자원 활용이 좋음 |
| 단점 | 대기 시간이 길어질 수 있음 | 코드 흐름이 복잡해질 수 있음 |
| 사용 예 | 파일 처리, DB 트랜잭션, 순차 계산 | 네트워크, 이벤트 처리, 인터럽트, DMA |
블로킹이란?
블로킹(Blocking)은 작업이 끝날 때까지 호출한 쪽이 멈춰서 기다리는 방식이다. 초점이 "작업의 완료 처리 구조"가 아니라 "호출한 흐름이 멈추는가"에 있다는 점에 유의해야 한다.
예를 들어 Verilog 블로킹 할당(=)의 코드를 보면 아래와 같이 작성이 가능하다
initial
begin
A = 1'b0; B = 1'b0;
end
always @ (posedge CLK)
begin
A = A + 1; // A = 1
B = A + 1; // B = 2
end
A와 B는 0으로 초기화된다. 블로킹 할당은 한 문장이 끝난 뒤에 다음 문장이 실행되는 순차적 의미를 가지므로, A = A + 1이 먼저 적용되어 A가 1이 되고, 이어지는 B = A + 1은 이미 갱신된 A(=1)를 사용하여 B가 2가 된다. 주석에 표시된 A = 1, B = 2는 이 순차적 갱신의 결과다.
요약하자면 아래와 같다.
| 항목 | 설명 |
| 호출한 쪽 | 작업 완료까지 대기 |
| 코드 흐름 | 단순함 |
| 장점 | 처리 순서가 명확함 |
| 단점 | 대기 시간이 길면 전체 프로그램이 멈춘 것처럼 보일 수 있음 |
| 사용 예 | blocking read, sleep, delay, 동기 DB 요청 |
논블로킹이란?
논블로킹(Non-blocking)은 작업이 끝나지 않아도 호출한 쪽이 멈추지 않고 바로 다음 작업을 진행하는 방식이다. 블로킹과 대칭되는 개념으로, 호출한 흐름의 정지 여부가 반대다.
예를 들어 Verilog 논블로킹 할당(<=)의 코드를 보면 아래와 같이 작성이 가능하다.
initial
begin
A = 1'b0; B = 1'b0;
end
always @ (posedge CLK)
begin
A <= A + 1; // A = 1
B <= A + 1; // B = 1
end
블로킹 예제와 코드 구조는 같지만 결과가 다르다. 논블로킹 할당은 우변을 먼저 모두 평가한 뒤 좌변을 갱신하므로, A와 B의 우변 모두 갱신 이전의 A(=0)를 참조한다. 따라서 A와 B가 각각 0+1, 즉 동일하게 1이 된다. 주석의 A = 1, B = 1은 이 동시 갱신의 결과다. 블로킹 예제에서 B가 2였던 것과 비교하면 두 방식의 의미 차이가 분명하게 드러난다.
요약하자면 아래와 같다.
| 항목 | 설명 |
| 호출한 쪽 | 작업 완료를 기다리지 않음 |
| 코드 흐름 | 복잡해질 수 있음 |
| 장점 | 시스템이 멈추지 않음 |
| 단점 | 완료 여부를 따로 확인해야 함 |
| 사용 예 | nonblocking socket, polling, event loop |
동기 / 비동기와 블로킹 / 논블로킹의 차이
동기/비동기와 블로킹/논블로킹은 자주 혼동되지만, 둘은 서로 다른 축을 본다. 정리하면서 가장 헷갈렸던 지점이 바로 이 구분이었다.
| 구분 | 기준 |
| 동기 / 비동기 | 작업 완료를 어떤 구조로 처리하는가 |
| 블로킹 / 논블로킹 | 호출한 쪽이 기다리는가, 기다리지 않는가 |
- 동기/비동기: 작업의 완료 처리 방식에 관한 개념
- 블로킹/논블로킹: 호출한 흐름이 멈추는지 여부에 관한 개념
두 축은 독립적이므로 서로 결합되어 함께 나타날 수 있다.
동기 + 블로킹
요청한 작업이 끝날 때까지 기다리고, 작업이 완료된 뒤 다음 코드를 실행하는 방식이다.
data = read_sensor();
process(data);
실행 흐름은 "센서 읽기 시작 → 센서 읽기 완료 → 데이터 처리 시작" 순으로 진행된다. read_sensor()가 끝나야 process(data)가 시작되므로, 호출 흐름이 멈춘 채(블로킹) 순차적으로(동기) 이어진다.
동기 + 논블로킹
작업 완료 여부를 직접 확인하지만, 준비되지 않았을 때 기다리지 않고 바로 다른 작업을 수행하는 방식이다.
if (sensor_ready()) {
data = read_sensor();
process(data);
} else {
do_other_work();
}
흐름은 "센서 준비 확인 → 아직 준비 안 됨 → 다른 작업 수행 → 다시 센서 준비 확인"으로 진행된다. 완료를 직접 확인한다는 점에서 동기적이지만, 준비되지 않았을 때 멈추지 않고 다른 작업으로 넘어간다는 점에서 논블로킹이다.
비동기 + 블로킹
비동기 작업을 시작했지만, 결과를 기다리면서 현재 흐름이 막히는 방식이다.
start_async_read();
wait_until_done();
process(data);
비동기 API를 사용하더라도 wait_until_done()처럼 결과를 기다리면 블로킹이 된다. 이 조합은 "비동기 = 논블로킹"이라는 오해를 직접 반박하는 사례로, 작업을 비동기로 시작했는지와 호출 흐름이 멈추는지가 별개임을 보여준다.
비동기 + 논블로킹
작업을 요청한 뒤 바로 다음 작업을 수행하고, 작업이 완료되면 콜백·이벤트·인터럽트 등으로 결과를 처리하는 방식이다.
start_dma_transfer();
while (1) {
do_other_work();
if (dma_done) {
process(data);
}
}
흐름은 "DMA 전송 시작 → CPU는 다른 작업 수행 → DMA 완료 인터럽트 발생 → 데이터 처리"로 진행된다. 작업을 시작한 뒤 호출 흐름이 멈추지 않고(논블로킹) 다른 일을 계속하다가, 완료 신호가 도착하면 결과를 처리한다(비동기). 임베디드에서 DMA와 인터럽트가 결합되는 전형적인 형태다.
'WiSoft' 카테고리의 다른 글
| UART · SPI · I2C · CAN (0) | 2026.06.26 |
|---|---|
| 배열 리스트와 링크드 리스트 (0) | 2026.06.26 |
| 비대칭키 암호화와 대칭키 암호화 (0) | 2026.06.18 |
| BST의 최악의 경우의 예와 시간 복잡도 (0) | 2026.06.17 |
| 캐시의 시간 지역성과 공간 지역성 (0) | 2026.06.16 |