๐ English Abstract
This article addresses critical performance bottlenecks in Python-based test and measurement automation systems utilizing SCPI (Standard Commands for Programmable Instruments) over serial interfaces. It provides an in-depth analysis of hardware RX/TX buffer overflows and inter-process communication (IPC) latency caused by multiprocessing overhead. Readers will learn practical refactoring strategies including single-producer serial architectures, non-blocking I/O ring buffers, and zero-copy shared memory synchronization.
ํ๋์จ์ด ๋ฐ ๋ฐ๋์ฒด ๊ฒ์ฌ ์ฅ๋น ์๋ํ ๋ถ์ผ์์ ํ์ด์ฌ(Python)์ PyVISA, PySerial๊ณผ ๊ฐ์ ํ๋ถํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ฐํ์ผ๋ก ๊ณ์ธก๊ธฐ ์ ์ด์ ํ์ค ํ์ค ์ธ์ด๋ก ์๋ฆฌ ์ก์์ต๋๋ค. ํนํ ์ค์ค๋ก์ค์ฝํ(Oscilloscope), ์ ์ ๊ณต๊ธ ์ฅ์น(Power Supply), ๋ฉํฐ๋ฏธํฐ(DMM) ๋ฑ ์๋ง์ ๊ณ์ธก๊ธฐ์ SCPI(Standard Commands for Programmable Instruments) ํ๋กํ ์ฝ๋ก ํต์ ํ๋ฉฐ ๊ณ ์ ๋ฐ์ดํฐ๋ฅผ ์์งํ ๋, ํ์ด์ฌ์ GIL(Global Interpreter Lock) ํ๊ณ๋ฅผ ๊ทน๋ณตํ๊ธฐ ์ํด multiprocessing ๋ชจ๋์ ๋์
ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
๊ทธ๋ฌ๋ ๊ณ ์ ์ํ๋ง ํ๊ฒฝ์์ ํ์ด์ฌ์ ๋ฉํฐํ๋ก์ธ์ฑ์ ์๋ชป ์ค๊ณํ๋ฉด, ์๋ฆฌ์ผ ํฌํธ(Serial Port/RS-232/USB Virtual COM) ๋ฐ์ดํฐ ์์ ๋ถ์์ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ(Buffer Overflow)๊ฐ ๋ฐ์ํ์ฌ ํ๋ ์์ด ์์ค๋๊ฑฐ๋, ํ๋ก์ธ์ค ๊ฐ ํต์ (IPC, Inter-Process Communication) ๊ณผ์ ์์ ๋ฝ(Lock) ๊ฒฝํฉ ๋ฐ ๋ฐ์ดํฐ ๋๊ธฐํ ๋ณ๋ชฉ ํ์(Bottleneck)์ด ๋ฐ์ํ์ฌ ์ ์ฒด ์์คํ ์ด ๋ฉ์ถ๋ ์ฌ๊ฐํ ๋ฌธ์ ์ ์ง๋ฉดํ๊ฒ ๋ฉ๋๋ค.
๋ณธ ํฌ์คํ ์์๋ ์ด๋ฌํ ์์คํ ๋ณ๋ชฉ์ ๊ทผ๋ณธ์ ์ธ ์์ธ์ ํ๋์จ์ด/OS ๋ ์ด์ด๋ถํฐ ํ์ด์ฌ ๋ฐํ์ ๋ ์ด์ด๊น์ง ์ ๋ฐํ๊ฒ ๋ถ์ํ๊ณ , ์ด๋ฅผ ์๋ฒฝํ ํด๊ฒฐํ๊ธฐ ์ํ ์ค๋ฌด ์ค์ฌ์ ํธ๋ฌ๋ธ์ํ ๊ฐ์ด๋ ๋ฐ ์ํคํ ์ฒ ๋ฆฌํฉํ ๋ง ๋ฐฉ์์ ์ ๊ณตํฉ๋๋ค.
1. ์๋ฆฌ์ผ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ์ IPC ๋ณ๋ชฉ์ ์์ธ ๋ถ์
ํธ๋ฌ๋ธ์ํ ์ ์์ํ๊ธฐ ์ , ๋ฌธ์ ์ ์์ธ์ด ๋ฌผ๋ฆฌ์ ์ธํฐํ์ด์ค ๋ฒํผ์์ ๋ฐ์ํ๋์ง, ์๋๋ฉด ํ์ด์ฌ ํ๋ก์ธ์ค ๊ฐ ๋ฐ์ดํฐ ์ ๋ฌ ๊ณผ์ ์์ ๋ฐ์ํ๋์ง ๋ช ํํ ๊ตฌ๋ถํด์ผ ํฉ๋๋ค.
๊ฐ. ๋ฌผ๋ฆฌ์ /OS ์๋ฆฌ์ผ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ (Hardware & OS UART Buffer Overflow)
๊ณ์ธก๊ธฐ์์ ์ ์ก๋๋ SCPI ํ
์คํธ ๋ฐ์ดํฐ(์: :MEASure:VOLTage:ALL?) ๋๋ ๋ฐ์ด๋๋ฆฌ ๋ธ๋ก ๋ฐ์ดํฐ๋ ์ปค๋์ UART ๋๋ผ์ด๋ฒ ์์ FIFO(First-In-First-Out) ๋ฒํผ์ ๋จผ์ ์์
๋๋ค.
- ๋๋ผ์ด๋ฒ ๋ ์ดํด์ ํ์(Latency Timer): FTDI ๋ฑ USB-to-Serial ์นฉ์ ์ ๊ธฐ๋ณธ Latency Timer ์ค์ ๊ฐ(๊ธฐ๋ณธ๊ฐ ๋ณดํต 16ms)์ผ๋ก ์ธํด ๋ฐ์ดํฐ ์์ ๋ธ๋ก์ด ์ง์ฐ๋๋ค๊ฐ ํ ๋ฒ์ ๋ชฐ๋ ค ์ค๋ฒํ๋ก์ฐ๋ฅผ ์ ๋ฐํฉ๋๋ค.
- ๋ ์ ์ ํ์ผ ํธ๋ค ์ก์ธ์ค ๊ฒฝ์: ์ฌ๋ฌ ํ์ ํ๋ก์ธ์ค(Child Processes)๊ฐ ๋์ผํ ์๋ฆฌ์ผ ํธ๋ค(COM Port)์ ๋์์ ์ ๊ทผ์ ์๋ํ๊ฑฐ๋, ์ฝ๊ธฐ ์์ ์ ๋ถํ์ํ ๋ธ๋กํน I/O(Blocking I/O)๋ฅผ ์ํํ ๊ฒฝ์ฐ ์ปค๋ ๋ฒํผ ๋น์ฐ๊ธฐ(Flush) ์๋๊ฐ ๋ฐ์ดํฐ ์ ์ ์๋๋ฅผ ๋ฐ๋ผ๊ฐ์ง ๋ชปํด Overrun Error๊ฐ ๋ฐ์ํฉ๋๋ค.
๋. ํ๋ก์ธ์ค ๊ฐ ํต์ (IPC) ๋ฐ์ดํฐ ๋๊ธฐํ ๋ณ๋ชฉ
ํ์ด์ฌ์ multiprocessing.Queue๋ Pipe๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ด๋ถ์ ์ผ๋ก ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํ(Pickling) ๋ฐ ์ญ์ง๋ ฌํ(Unpickling)ํฉ๋๋ค.
- Pickle ์ง๋ ฌํ ์ค๋ฒํค๋: ๊ณ์ธก๊ธฐ๋ก๋ถํฐ ์ด๋น ์์ฒ ๋ฒ ์์ง๋๋ SCPI ์๋ต ์คํธ๋ง ๋ฐ์ดํฐ๋ฅผ ๋งค๋ฒ
Queue.put()์ผ๋ก ์ ๋ฌํ๋ฉด ๋๋์ CPU ์ฐ์ฐ ์์์ด Pickling์ ์๋ชจ๋ฉ๋๋ค. - ํ์ดํ ๋ฒํผ ์ถฉ์ (Pipe Buffer Full): ํ์ ํ๋ก์ธ์ค๊ฐ ํ์์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ์๋๊ฐ ์์ฐ ํ๋ก์ธ์ค๋ณด๋ค ๋๋ฆฌ๋ฉด OS ํ์ดํ ๋ฒํผ๊ฐ ๊ฐ๋ ์ฐจ๋ฉด์ ์์ฐ์ ํ๋ก์ธ์ค๊ฐ
Queue.put()์์ ๋ฌดํ ๋ธ๋กํน(Deadlock) ์ํ์ ๋น ์ง๋๋ค.
2. ์๋ฆฌ์ผ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ํ๋์จ์ด ๋ฐ ๋๋ผ์ด๋ฒ ์ต์ ํ
๊ฐ์ฅ ๋จผ์ ๋ฌผ๋ฆฌ ๋ ์ด์ด์ OS ์ปค๋ ๋ ๋ฒจ์์ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ๊ฐ ๋ฐ์ํ์ง ์๋๋ก ์ค์ ์ ์ต์ ํํด์ผ ํฉ๋๋ค.
๊ฐ. FTDI ๋๋ผ์ด๋ฒ Latency Timer ๋ณ๊ฒฝ
USB-to-Serial ๋ณํ๊ธฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, Windows ์ฅ์น ๊ด๋ฆฌ์ ๋๋ Linux sysfs๋ฅผ ํตํด Latency Timer๋ฅผ 16ms์์ 1ms๋ก ์ถ์ํด์ผ ํฉ๋๋ค.
# Linux ํ๊ฒฝ์์ FTDI Latency Timer๋ฅผ 1ms๋ก ๋ณ๊ฒฝํ๋ ํฐ๋ฏธ๋ ๋ช
๋ น
echo 1 | sudo tee /sys/bus/usb-serial/devices/ttyUSB0/latency_timer
๋. ํ๋์จ์ด ํ๋ฆ ์ ์ด(RTS/CTS Flow Control) ์ ์ฉ
์ํํธ์จ์ด์ ์ธ XON/XOFF ๋ฐฉ์์ SCPI ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ ๋ด๋ถ ๋ฌธ์์ด๊ณผ ์ถฉ๋ํ ์ ์์ผ๋ฏ๋ก, ๋ฐ๋์ ํ๋์จ์ด RTS/CTS(Request to Send / Clear to Send) ๋ผ์ธ์ ํ์ฑํํ์ฌ ์์ ๋ฒํผ ๊ฐ๋ ์ฐธ ์ํ๋ฅผ ๊ณ์ธก๊ธฐ ํ๋์จ์ด์ ํต๋ณดํ๋๋ก ์ค์ ํฉ๋๋ค.
import serial
# RTS/CTS ํ๋์จ์ด ํ๋ฆ ์ ์ด๊ฐ ์ ์ฉ๋ ์๋ฆฌ์ผ ํฌํธ ์ค์ ์์
ser = serial.Serial(
port='COM3',
baudrate=115200,
timeout=0.1,
rtscts=True # RTS/CTS Hardware Flow Control ํ์ฑํ
)
3. ์ํํธ์จ์ด ์ํคํ ์ฒ ๋ฆฌํฉํ ๋ง: ๋จ์ผ ์์ฐ์ ํจํด๊ณผ Zero-Copy ๊ณต์ ๋ฉ๋ชจ๋ฆฌ
์ํํธ์จ์ด ๋ ์ด์ด์์๋ ๋จ์ผ ์์ฐ์(Single Producer - Dedicated Reader) ํจํด์ ๋์
ํ๊ณ , IPC ์ง๋ ฌํ ๋ณ๋ชฉ์ ์ ๊ฑฐํ๊ธฐ ์ํด multiprocessing.shared_memory๋ฅผ ํ์ฉํ Zero-Copy ๋ง ๋ฒํผ(Circular Ring Buffer) ์ํคํ
์ฒ๋ฅผ ๊ตฌํํด์ผ ํฉ๋๋ค.
๊ฐ. Dedicated Serial Reader ํ๋ก์ธ์ค ๋ถ๋ฆฌ
์๋ฆฌ์ผ ํฌํธ ํต์ ๊ถํ์ ์ค์ง ๋จ ํ๋์ dedicated ํ๋ก์ธ์ค๋ง ๋ณด์ ํฉ๋๋ค. ๋ค๋ฅธ ์์ปค ํ๋ก์ธ์ค๋ ์๋ฆฌ์ผ ํฌํธ์ ์ง์ ์ ๊ทผํ์ง ์๊ณ , ๊ณต์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํตํด์๋ง ์์ง๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด๊ฐ๋๋ค.
๋. SharedMemory์ Ring Buffer๋ฅผ ํ์ฉํ IPC ์ต์ ํ
ํ์ด์ฌ 3.8 ์ด์์์ ์ง์ํ๋ multiprocessing.shared_memory.SharedMemory๋ฅผ ์ฌ์ฉํ๋ฉด Queue์ Pickle ์ค๋ฒํค๋๋ฅผ ์์ ํ ์ ๊ฑฐํ ์ ์์ต๋๋ค.
import multiprocessing as mp
from multiprocessing import shared_memory
import numpy as np
import time
import serial
class SharedRingBuffer:
"""
Multiprocessing ๊ฐ Zero-Copy ๋ฐ์ดํฐ ์ ์ก์ ์ํ Ring Buffer ํด๋์ค
"""
def __init__(self, size=1000, item_size=8, shm_name=None):
self.size = size
self.item_size = item_size
self.buffer_bytes = size * item_size
if shm_name is None:
# ์์ฐ์ ํ๋ก์ธ์ค: ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์์ฑ
self.shm = shared_memory.SharedMemory(create=True, size=self.buffer_bytes + 16) # ํค๋ 16๋ฐ์ดํธ ์ถ๊ฐ
self.is_owner = True
else:
# ์๋น์ ํ๋ก์ธ์ค: ๊ธฐ์กด ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ์ฐ๊ฒฐ
self.shm = shared_memory.SharedMemory(name=shm_name)
self.is_owner = False
# ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๋ฒํผ๋ฅผ NumPy ๋ฐฐ์ด๋ก ๋งคํ (Zero-Copy)
self.data_arr = np.ndarray((size,), dtype=np.float64, buffer=self.shm.buf[16:])
# ํค๋: [0~7] write_index, [8~15] read_index (uint64)
self.header = np.ndarray((2,), dtype=np.uint64, buffer=self.shm.buf[:16])
def write(self, val):
w_idx = self.header[0]
self.data_arr[w_idx % self.size] = val
self.header[0] = w_idx + 1 # Atomic-like index update
def read_available(self):
w_idx = self.header[0]
r_idx = self.header[1]
if r_idx >= w_idx:
return np.array([])
# ์ฝ์ ๋ฐ์ดํฐ ์ฌ๋ผ์ด์ฑ
count = min(w_idx - r_idx, self.size)
start = r_idx % self.size
end = (r_idx + count) % self.size
if start < end:
data = np.copy(self.data_arr[start:end])
else:
data = np.concatenate((self.data_arr[start:], self.data_arr[:end]))
self.header[1] = r_idx + count
return data
def close(self):
self.shm.close()
if self.is_owner:
self.shm.unlink()
4. ์ค์ ํ์ดํ๋ผ์ธ ๊ตฌํ: SCPI ๋น๋๊ธฐ ํ์ฑ ๋ฐ ์์ปค ๋ฉํฐํ๋ก์ธ์ฑ
์๋ ์์ ๋ ๊ณ์ธก๊ธฐ๋ก๋ถํฐ SCPI ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋น๋๊ธฐ๋ก ์ฝ์ด ๋ค์ฌ ๋ง ๋ฒํผ์ ๊ธฐ๋กํ๋ ์์ฐ์ ํ๋ก์ธ์ค์, ์ด๋ฅผ ์์ ํ์ฌ ์ค์๊ฐ ํต๊ณ ์ฐ์ฐ์ ์ํํ๋ ์๋น ํ๋ก์ธ์ค์ ์์ฑํ ์ํคํ ์ฒ ์์์ ๋๋ค.
import multiprocessing as mp
import time
import numpy as np
import re
def scpi_producer_process(shm_name, stop_event, port_name):
"""
๋จ์ผ ์๋ฆฌ์ผ ์ฝ๊ธฐ ๋ฐ SharedMemory ๊ธฐ๋ก ์ ์ฉ ํ๋ก์ธ์ค
"""
# ๋ง ๋ฒํผ ์ฐ๊ฒฐ
ring_buf = SharedRingBuffer(size=5000, shm_name=shm_name)
# ์๋ฆฌ์ผ ๊ฐ์ ์๋ฎฌ๋ ์ด์
๋ฐ ํฌํธ ์ฐ๊ฒฐ ์ค์
# try:
# ser = serial.Serial(port_name, 115200, timeout=0.01, rtscts=True)
# except Exception as e:
# print(f"Port Open Fail: {e}")
# return
# ์ ๊ทํํ์ ์ฌ์ ์ปดํ์ผ (SCPI ASCII ํ์ฑ ์๋ ์ต์ ํ)
scpi_float_pattern = re.compile(rb'[-+]?\d*\.\d+|\d+')
print("[Producer] Started reading SCPI stream...")
# ๊ฐ์ SCPI ์คํธ๋ฆผ ์๋ฎฌ๋ ์ด์
๋ฃจํ
counter = 0
while not stop_event.is_set():
# ์ค์ ํ๊ฒฝ์์๋ ser.read_until(b'\n') ๋๋ ser.read(ser.in_waiting) ์ฌ์ฉ
# dummy SCPI response: b":VOLT 12.345 V\n"
raw_bytes = f":VOLT {10.0 + (counter % 50) * 0.1:.3f} V\n".encode('ascii')
counter += 1
# 1. ๋น ๋ฅธ SCPI ์ซ์๋ฅผ ์ถ์ถ
match = scpi_float_pattern.search(raw_bytes)
if match:
try:
val = float(match.group())
# 2. Shared Memory ๋ง ๋ฒํผ์ ๊ธฐ๋ก (Lock Free Concept)
ring_buf.write(val)
except ValueError:
pass
time.sleep(0.001) # 1kHz ๊ณ์ธก ์ํ๋ง ์๋ ํ๋ด
ring_buf.close()
print("[Producer] Terminated cleanly.")
def consumer_worker_process(shm_name, stop_event):
"""
๊ณต์ ๋ฉ๋ชจ๋ฆฌ์์ ๊ณ ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ๋ถ์ํ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ๋ก์ธ์ค
"""
ring_buf = SharedRingBuffer(size=5000, shm_name=shm_name)
print("[Consumer] Worker process started...")
processed_count = 0
while not stop_event.is_set():
data = ring_buf.read_available()
if len(data) > 0:
processed_count += len(data)
# ์์ง ๋ฐ์ดํฐ ๋ฐฐ์น ์ฐ์ฐ (์: ์ค์๊ฐ ์ด๋ ํ๊ท ๋๋ FFT)
avg_val = np.mean(data)
# print(f"[Consumer] Batch read: {len(data)} items, Avg: {avg_val:.2f}")
else:
time.sleep(0.005) # CPU idle ๋ฐฉ์ง
ring_buf.close()
print(f"[Consumer] Total processed points: {processed_count}")
if __name__ == "__main__":
# 1. ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ๋ฉ์ธ ๊ด๋ฆฌ์ ์ด๊ธฐํ
main_buf = SharedRingBuffer(size=5000)
shm_name = main_buf.shm.name
stop_event = mp.Event()
# 2. ํ๋ก์ธ์ค ์์ฑ ๋ฐ ์คํ
producer = mp.Process(target=scpi_producer_process, args=(shm_name, stop_event, "COM3"))
consumer = mp.Process(target=consumer_worker_process, args=(shm_name, stop_event))
producer.start()
consumer.start()
try:
# 5์ด๊ฐ ๋ฉ์ธ ๋ชจ๋ํฐ๋ง ์คํ
time.sleep(5)
finally:
print("[Main] Stopping all processes...")
stop_event.set()
producer.join()
consumer.join()
main_buf.close()
print("[Main] System successfully shut down.")
5. ํ์ ํธ๋ฌ๋ธ์ํ ์ฃ์ง ์ผ์ด์ค ๋ฐ ์ฒดํฌ๋ฆฌ์คํธ
์ค์ ์ฅ๋น ๊ฒ์ฌ ์๋ํ ๋ผ์ธ(24/7 ์ฐ๋)์ ์ ์ฉํ ๋ ์์ฃผ ๋ง๋๋ ์ฃ์ง ์ผ์ด์ค์ ํด๊ฒฐ ์ฒดํฌ๋ฆฌ์คํธ์ ๋๋ค.
๊ฐ. USB ์๋ฆฌ์ผ ๋ฆฌ์๋ด๋จธ๋ ์ด์ (Re-enumeration) ๋ฐ ํฌํธ ์ดํ
๊ณ ์ ์/๋์ ๋ฅ ๊ณ์ธก๊ธฐ ์ ์ด ์ค ๋ฐ์ํ๋ ๋ ธ์ด์ฆ(EMI/ESD)๋ก ์ธํด USB ๊ฐ์ COM ํฌํธ์ ์ฐ๊ฒฐ์ด ์๊ฐ์ ์ผ๋ก ๋๊ฒผ๋ค ์ฌ์ฐ๊ฒฐ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ํด๊ฒฐ์ฑ
: Producer ํ๋ก์ธ์ค ๋ด๋ถ์
PySerial.SerialException๋ฐ์ ์ ์๋ ์ฌ์ฐ๊ฒฐ(Reconnection Retry Loop) ๋ก์ง์ ๊ตฌ๋นํ๊ณ , ๋ณต๊ตฌ๋๋ ๋์ Shared Memory์ ์ธ๋ฑ์ค๋ฅผ ์์ ํ๊ฒ ๋ฆฌ์ ํด์ผ ํฉ๋๋ค.
๋. SCPI ์ข ๋จ ๋ฌธ์(Termination Character) ํผ์
๊ณ์ธก๊ธฐ ์ ์กฐ์ฌ(Agilent/Keysight, Tektronix, Rohde & Schwarz)๋ง๋ค ๊ธฐ๋ณธ ์ข
๋จ ๋ฌธ์๊ฐ \n(LF), \r\n(CRLF), ๋๋ EOI(End or Identify) ๋ผ์ธ ํ์ฑํ ์ฌ๋ถ๋ก ๋ค๋ฆ
๋๋ค.
- ํด๊ฒฐ์ฑ
: ์๋ฆฌ์ผ ์ฝ๊ธฐ ์
read_until()ํจ์์ ์ฌ์ฉํ ์ข ๋จ ๋ฌธ์๋ฅผ ๋ช ํํ ์ง์ ํ๊ณ , ๋ฐ์ด๋๋ฆฌ ๋ธ๋ก ๋ฐ์ดํฐ ์ ์ก ๋ชจ๋(FORM:DATA REAL,32) ์ฌ์ฉ ์์๋ ํค๋์ ๋ฐ์ดํฐ ๊ธธ์ด๋ฅผ ๋จผ์ ๊ณ์ฐํ ํ ์ ํํ ๋ฐ์ดํธ ์๋งํผread(bytes_to_read)๋ก ์ฝ์ด ๋ค์ฌ์ผ ๋ฒํผ ์ค๋ฒ๋ฐ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
๋ค. ํ์ด์ฌ ํ๋ก์ธ์ค ๊ณ ์ฌ(Zombie Process) ๋ฐ SharedMemory ๋์
ํ๋ก์ธ์ค๊ฐ ์์ธ(Exception)๋ก ๋น์ ์ ์ข
๋ฃ๋๋ฉด SharedMemory๊ฐ OS ๋ฉ๋ชจ๋ฆฌ์ ๋จ์ ๋ฉ์ธํ๋ ์ ์ฌ์์ ์ ๊น์ง RAM ๋์๋ฅผ ์ผ์ผํต๋๋ค.
- ํด๊ฒฐ์ฑ
: ๋ฉ์ธ ํ๋ก์ธ์ค์
try...finally๊ตฌ๋ฌธ ๋ด์์shm.close()๋ฐshm.unlink()๋ฅผ ๋ช ์์ ์ผ๋ก ํธ์ถํ๊ฑฐ๋,atexit๋ชจ๋์ ํด์ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํด์ผ ํฉ๋๋ค.
6. ๊ฒฐ๋ก : ์์ ์ ์ธ ๊ณ์ธก ์๋ํ ์์คํ ๊ตฌ์ถ์ ์ํ ํต์ฌ ์ ์ธ
ํ์ด์ฌ์ ํ์ฉํ ๊ณ ์ SCPI ๊ณ์ธก๊ธฐ ์๋ํ ์ ์ด ์ ๋ฐ์ํ๋ ์๋ฆฌ์ผ ๋ฒํผ ์ค๋ฒํ๋ก์ฐ ๋ฐ ๋ฐ์ดํฐ ๋๊ธฐํ ๋ณ๋ชฉ์ ๋จ์ํ ์ฝ๋ ๊ตฌ์กฐ ๋ณ๊ฒฝ๋ง์ผ๋ก๋ ์๋ฒฝํ ํด๊ฒฐํ๊ธฐ ์ด๋ ต์ต๋๋ค.
- ํ๋์จ์ด ๋ ์ด์ด: USB ๋๋ผ์ด๋ฒ Latency ๊ฐ์(1ms) ๋ฐ RTS/CTS ํ๋ฆ ์ ์ด๋ฅผ ์ ์ ํ ์ค์ ํด์ผ ํฉ๋๋ค.
- ์ํคํ ์ฒ ๋ ์ด์ด: ์๋ฆฌ์ผ ํฌํธ ์ฝ๊ธฐ๋ ๋จ ํ๋ ์ Dedicated Producer Process๋ง ๋ด๋นํ๋๋ก ๋จ์ผํํฉ๋๋ค.
- IPC ๋ ์ด์ด: Heavyํ Queue ๋์ Zero-Copy SharedMemory ๋ง ๋ฒํผ๋ฅผ ํ์ฉํ์ฌ ๋ฐ์ดํฐ ์ง๋ ฌํ ๋ณ๋ชฉ์ ์ ๊ฑฐํฉ๋๋ค.
์ด๋ฌํ ์ต์ ํ ํจํด์ ์ค๊ณ์ ์ ์ฉํ๋ฉด ์ด๋น ์๋ง ๊ฑด ์ด์์ ๊ณ์ธก ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ดํฐ ์์ค ์์ด ์ค์๊ฐ์ผ๋ก ์์ง ๋ฐ ๋ถ์ํ๋ ๊ณ ์ฑ๋ฅ ์๋ํ ๊ฒ์ฌ ์์คํ ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค.