Skip to main content
Robotics

Lock-free vs Mutex: 로봇 제어 시스템 IPC 성능 벤치마크

로봇 제어 시스템의 IPC 성능을 결정하는 요인은 프로세스 경계가 아닌 동기화 메커니즘입니다. Mutex 기반 78-103µs에서 Lock-free로 0.74-0.82µs를 달성한 100배 개선 사례를 공유합니다.

WRWIM Robotics Team
·
roboticsipclock-freemutexreal-timeperformance

Lock-free vs Mutex: 로봇 제어 시스템 IPC 성능 벤치마크

"In-Process 통신이 Inter-Process 통신보다 빠르다"는 직관은 틀렸습니다.

성능을 결정하는 것은 프로세스 경계가 아니라 동기화 메커니즘입니다.

이 글에서는 로봇 제어 시스템을 시뮬레이션하는 4단계 파이프라인에서 Mutex 기반과 Lock-free 기반 동기화의 성능을 비교합니다.

결론 먼저

IPC 방식최적화 전 (Mutex)최적화 후 (Lock-free)개선
in_process78-103 µs0.74-0.82 µs~100배
shared_memory0.7-0.8 µs0.75-0.78 µs변화 없음
pipe33-106 µs68-87 µs변화 없음

Lock-free 적용 후 in_process와 shared_memory가 동일한 성능을 달성합니다.

테스트 환경

4단계 파이프라인 (로봇 제어 시뮬레이션)

Planner → IK Solver → EtherCAT Master → Mock Hardware
단계처리 내용
PlannerCartesian 궤적 생성
IK Solver관절 각도 계산
EtherCAT MasterEtherCAT 프레임 생성
Mock Hardware액추에이터 응답 시뮬레이션

테스트 조건

파라미터
주기1ms, 2ms, 4ms, 10ms
테스트 시간10초/테스트
웜업100 iterations
자유도6 DOF
메시지 크기고정 (동적 할당 없음)

측정 메트릭

  • Cycle Latency: 전체 파이프라인 왕복 시간
  • Jitter: 레이턴시 변동
  • Percentiles: P50, P95, P99, P99.9
  • Deadline Misses: 주기 시간 초과 횟수

왜 Mutex가 느린가?

Mutex의 숨겨진 비용

연산레이턴시
비경쟁 mutex lock~25-75 ns
경쟁 mutex lock~1-15 µs (커널 futex 호출)
Condition variable notify~2-10 µs
스레드 웨이크업~10-50 µs (컨텍스트 스위칭)
통신당 총합~50-100 µs

Mutex 통신 흐름

Thread A          Kernel           Thread B
│ │ │
├── mutex.lock() ►│ │
│ (futex syscall) │
│◄── acquired ────│ │
│ [critical section] │
├── cv.notify() ──►│── wakeup ─────►│
│ (futex syscall) (scheduling) │
│ │ │
└────────── Total ~50-100µs ────────┘

핵심 문제: 경쟁 상황에서 커널 개입(futex syscall)이 발생합니다.

Lock-free의 원리

Lock-free 비용

연산레이턴시
atomic_store (release)~10-20 ns
atomic_load (acquire)~10-20 ns
std::this_thread::yield()~100-500 ns
커널 개입없음
통신당 총합~0.7-0.8 µs

Lock-free 통신 흐름

Thread A                              Thread B
│ │
├── atomic_store() ──────────────────►│
│ (single CPU instruction, ~10ns) │
│ ├── atomic_load()
│ │ (single CPU instruction)
│ │
└────────── Total ~0.7-0.8µs ─────────┘

핵심 차이: 커널 개입 없이 CPU 명령어만으로 동기화합니다.

x86 Memory Ordering

x86 아키텍처는 강한 메모리 모델을 가지므로:

  • memory_order_acquire/release에 추가 명령어가 필요 없음
  • 사실상 제로 오버헤드

상세 벤치마크 결과

최적화 후 (Lock-free)

IPC 방식주기Mean (µs)P99 (µs)Jitter (µs)Misses
in_process1ms0.791.90999.210
in_process2ms0.741.341999.260
in_process4ms0.761.413999.240
in_process10ms0.822.309999.180
shared_memory1ms0.781.29999.220
shared_memory2ms0.761.791999.240
shared_memory4ms0.751.453999.250
shared_memory10ms0.771.829999.230
pipe1ms68.92174.00931.080
pipe2ms86.62179.071913.380
pipe4ms79.47173.843920.530
pipe10ms82.06174.799917.940

최종 성능 순위

  1. in_process (Lock-free): 0.74 µs
  2. shared_memory (Lock-free): 0.75 µs
  3. pipe (Kernel IPC): 68.92 µs (~90배 느림)

왜 Lock-free에서 In-Process = Shared Memory인가?

둘 다 동일한 Lock-free Atomic 패턴을 사용합니다:

  • 동일한 spin-wait 메커니즘
  • 유일한 차이: 메모리 위치 (힙 vs 공유 메모리)

메모리 위치는 성능에 영향을 주지 않습니다.

Lock-free 구현 체크리스트

  1. 캐시 라인 정렬 (False Sharing 방지)
alignas(64) std::atomic<size_t> writeIdx_;  // 64바이트 정렬
alignas(64) std::atomic<size_t> readIdx_;
  1. 올바른 Memory Ordering (release/acquire 시맨틱스)
buffer_[writeIdx].store(data, std::memory_order_release);
auto data = buffer_[readIdx].load(std::memory_order_acquire);
  1. 2의 거듭제곱 버퍼 크기 (빠른 모듈로 연산)
constexpr size_t BUFFER_SIZE = 8192;  // 2^13
size_t next = (current + 1) & (BUFFER_SIZE - 1); // % 대신 &
  1. 고정 크기 메시지 (동적 할당 없음)

흔한 구현 실수

실수문제
Non-atomic 연산 사용데이터 레이스
memory_order_relaxed순서 보장 없음
캐시 라인 정렬 누락False Sharing

아키텍처 선택: In-Process vs Inter-Process

기준In-Process (Lock-free)Inter-Process
레이턴시~0.7 µs~50-200 µs
결정성매우 높음커널 스케줄러 의존
장애 격리없음프로세스 수준 격리
장애 동작전체 정지 (Fail-Stop)부분 운영 (위험)
복구 방법전체 재시작개별 프로세스 재시작
메모리 보호없음 (버그가 전체 손상)주소 공간 분리
디버깅쉬움분산 트레이싱 필요

로봇 제어에서 Fail-Stop이 중요한 이유

시나리오: IK Solver 프로세스 크래시

아키텍처동작결과
Inter-Process다른 프로세스 계속 실행모터가 오래된 명령으로 계속 동작 → 비제어 상태
In-Process전체 프로세스 정지모터 브레이크 자동 체결 → 안전 상태

"부분 장애가 완전 정지보다 위험합니다."

권장 아키텍처: 하이브리드

┌─────────────────────────────────────────────────────────┐
│ 실시간 제어 코어 (In-Process, Lock-free) │
│ Planner → IK → EtherCAT → Motor Driver │
│ • 1kHz+ 제어 루프 │
│ • 장애 시 Fail-Stop │
│ • Lock-free Atomic 동기화 │
├─────────────────────────────────────────────────────────┤
│ IPC (Shared Memory / Socket) - Non-realtime │
├─────────────────────────────────────────────────────────┤
│ [Camera] [UI Server] [Logging] [Monitoring] │
│ • 개별 프로세스 장애 허용 │
│ • 독립적 재시작 가능 │
│ • 실시간 코어에 영향 없음 │
└─────────────────────────────────────────────────────────┘

사용 사례별 권장사항

시나리오권장 방식이유
1kHz+ 실시간 제어In-Process + Lock-free최저 레이턴시, Fail-Stop
다중 머신 분산Inter-Process + Socket네트워크 통신 필요
프로세스 격리 필요Inter-Process + SHM보안/안정성
빠른 프로토타이핑In-Process + Mutex구현 단순
프로덕션 로봇하이브리드실시간 코어 + 비실시간 서비스

동기화 메커니즘 선택 기준

요구사항권장
< 10µs 레이턴시 필요Lock-free Atomic (~0.7-1 µs, 높은 복잡도)
> 100µs 레이턴시 허용Mutex 기반 큐 (~50-100 µs, 단순 구현)

핵심 정리

  1. "성능은 동기화 메커니즘이 결정한다." 프로세스 경계가 아닙니다.

    • Mutex 기반 in_process: 78-103 µs
    • Lock-free shared_memory: 0.7-0.8 µs
  2. Lock-free 적용 시 in_process와 shared_memory는 동일 성능입니다. 둘 다 ~0.7 µs.

  3. Mutex의 숨겨진 비용: 경쟁 상황에서 커널 futex 호출로 ~50-100 µs 지연.

  4. Lock-free의 핵심: 커널 개입 없이 CPU atomic 명령어만 사용.

  5. 로봇 제어에서 Fail-Stop이 중요: 부분 장애가 완전 정지보다 위험합니다.

  6. 하이브리드 아키텍처 권장: 실시간 코어는 In-Process + Lock-free, 비실시간 서비스는 Inter-Process.