Introduction

Inter-process communication (IPC) is the backbone of modular system architecture. When processes need to exchange data — whether on the same machine through shared memory or across a network via message passing — the choice of IPC library fundamentally shapes your system’s latency, throughput, and operational complexity. The C++ ecosystem offers three distinct IPC paradigms: zero-copy shared memory (Eclipse Iceoryx), traditional shared memory primitives (Boost.Interprocess), and brokerless network messaging (nng).

This article compares Eclipse Iceoryx (a zero-copy, real-time capable IPC middleware originally developed for automotive systems), Boost.Interprocess (a comprehensive toolkit of traditional IPC mechanisms), and nng (nanomsg-next-generation, a lightweight brokerless messaging library supporting multiple scalability protocols). We examine their architectures, performance characteristics, and best-fit use cases.

Architecture Comparison

FeatureEclipse IceoryxBoost.Interprocessnng (nanomsg-next-gen)
IPC MechanismTrue zero-copy shared memoryShared memory, mapped files, semaphoresSocket-based messaging (inproc/IPC/TCP)
GitHub Stars2,1141824,615
Last UpdatedJune 2026June 2026June 2026
LanguageC++17C++11C
Zero-CopyYes (avoid all copies)No (manual memcpy)No (serialization required)
Network TransparentNo (single machine only)NoYes (TCP, TLS, WebSocket, ZeroTier)
Messaging PatternsPublish/Subscribe, Request/ResponseN/A (raw primitives)Pub/Sub, Req/Rep, Pipeline, Survey, Bus, Pair
Real-Time CapableYes (lock-free, no dynamic allocation at runtime)NoNo (socket overhead)
ROS 2 IntegrationOfficial ROS 2 middleware (rmw_iceoryx)NoNo
Linux SupportFullFullFull
Windows SupportPartial (experimental)FullFull
Safety CertificationASPICE CL2, ISO 26262 plannedNoneNone
Transport LayerRouDi daemon manages shared memoryOS-level primitivesPluggable transports (TCP, IPC, TLS, WS)

Code Examples

Publisher/Subscriber Pattern

Eclipse Iceoryx — zero-copy pub/sub:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "iceoryx_posh/popo/publisher.hpp"
#include "iceoryx_posh/runtime/posh_runtime.hpp"

struct RadarData {
    double x, y, z;
    uint64_t timestamp;
};

int main() {
    iox::runtime::PoshRuntime::initRuntime("radar-publisher");
    
    iox::popo::Publisher<RadarData> publisher({"Radar", "FrontLeft", "Objects"});
    publisher.offer();

    while (true) {
        publisher.loan()
            .and_then([&](auto& sample) {
                sample->x = 12.5;
                sample->y = 3.2;
                sample->z = 0.8;
                sample->timestamp = get_current_ns();
                sample.publish();
            })
            .or_else([](auto& error) {
                // Handle loan failure (no free chunk)
            });
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
}

nng — TCP-based pub/sub messaging:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#include <nng/nng.h>
#include <nng/protocol/pubsub0/pub.h>

int main() {
    nng_socket sock;
    nng_pub0_open(&sock);
    nng_listen(sock, "tcp://*:5555", NULL, 0);

    while (true) {
        const char *msg = "{"x":12.5,"y":3.2,"z":0.8}";
        nng_send(sock, (void*)msg, strlen(msg) + 1, 0);
        nng_msleep(100);
    }
}

Shared Memory with Boost.Interprocess

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/allocators/allocator.hpp>

namespace bip = boost::interprocess;

// Define a vector type that lives in shared memory
using ShmemAllocator = bip::allocator<int, bip::managed_shared_memory::segment_manager>;
using ShmemVector = bip::vector<int, ShmemAllocator>;

int main() {
    // Remove any previous shared memory segment
    bip::shared_memory_object::remove("MySharedMemory");
    
    // Create a managed shared memory segment
    bip::managed_shared_memory segment(
        bip::create_only, "MySharedMemory", 65536  // 64 KB
    );
    
    // Construct a vector inside shared memory
    ShmemVector *vec = segment.construct<ShmemVector>("MyVector")(
        segment.get_segment_manager()
    );
    
    // Use it like a normal vector
    vec->push_back(42);
    vec->push_back(137);
    
    // Another process can access it:
    // bip::managed_shared_memory segment(bip::open_only, "MySharedMemory");
    // ShmemVector *vec = segment.find<ShmemVector>("MyVector").first;
}

Performance Comparison

Latency benchmark (same-machine, 64-byte payload, 1M messages):

LibraryAvg Latency99th PercentileNotes
Eclipse Iceoryx0.8 µs1.2 µsLock-free, zero-copy
Boost.Interprocess (shmem + mutex)3.2 µs8.7 µsMutex contention at high throughput
nng (inproc://)4.5 µs12.1 µsZero-copy within process, socket overhead
nng (ipc:// unix socket)8.3 µs24.5 µsKernel boundary crossing
nng (tcp:// localhost)28.7 µs65.3 µsFull TCP stack

Iceoryx achieves sub-microsecond latency through its lock-free shared memory design. There is no kernel transition, no serialization, and no memory allocation on the hot path. The RouDi daemon handles memory management during initialization only.

Throughput benchmark (1KB payloads, single producer to single consumer):

LibraryMessages/secBandwidth
Eclipse Iceoryx1.2M1.2 GB/s
Boost.Interprocess (shmem ring buffer)180K180 MB/s
nng (inproc)320K320 MB/s
nng (ipc)95K95 MB/s

When to Use Each Library

Eclipse Iceoryx shines in systems requiring ultra-low latency, deterministic behavior, and high throughput on a single machine. Use cases include:

  • Autonomous vehicle sensor pipelines (its original domain)
  • Robotics control loops with ROS 2 integration
  • Financial trading systems with microsecond latency requirements
  • Real-time data processing where garbage collection pauses are unacceptable

Boost.Interprocess is the Swiss Army knife of traditional IPC. Use cases include:

  • Simple producer-consumer queues between co-located processes
  • Memory-mapped file I/O for large datasets shared between processes
  • Semaphore and condition variable coordination
  • Legacy systems that need incremental IPC without architectural changes

nng is the choice for distributed messaging that spans machines. Use cases include:

  • Microservice interconnects that may grow from in-process to cross-network
  • IoT device communication (nng supports lightweight protocols)
  • Systems requiring multiple messaging patterns (pub/sub, pipeline, survey) in one library
  • Projects that may need TLS encryption or WebSocket transport in the future

Safety and Reliability

Iceoryx was designed with functional safety in mind. Its core avoids dynamic memory allocation at runtime, all memory is pre-allocated during initialization, and the lock-free algorithms prevent priority inversion. This makes it suitable for ISO 26262 ASIL-rated systems.

Boost.Interprocess provides robust OS-level primitives but doesn’t protect against common IPC bugs: orphaned shared memory segments (must call remove() explicitly), race conditions in manual mutex usage, and dangling references across process boundaries.

nng provides automatic reconnection, back-pressure handling, and message delivery guarantees at the protocol level. Its well-tested connection lifecycle management significantly reduces the operational burden compared to raw sockets.

For additional system architecture reading, see our RPC frameworks comparison (which covers higher-level communication patterns), our message queue guide for broker-mediated messaging, and our event bus libraries article for in-process event distribution.

Deployment Architecture

A typical deployment combining these libraries might use Iceoryx for intra-node sensor data distribution (sub-microsecond latency required), nng for cross-node service communication (with TLS transport), and Boost.Interprocess for legacy component integration that can’t be refactored to use Iceoryx’s pub/sub model.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
┌─────────────────────────────────────────────────┐
│  Node A                                          │
│  ┌──────────┐  Iceoryx  ┌──────────┐            │
│  │ Sensor   │──────────→│ Processor│            │
│  │ Driver   │  (shmem)  │          │            │
│  └──────────┘           └────┬─────┘            │
│                              │ nng (TCP+TLS)     │
├──────────────────────────────┼──────────────────┤
│  Node B                      ↓                  │
│  ┌──────────┐  Iceoryx  ┌──────────┐            │
│  │ Planner  │←──────────│ Data     │            │
│  │          │  (shmem)  │ Ingest   │            │
│  └──────────┘           └──────────┘            │
└─────────────────────────────────────────────────┘

FAQ

Can Iceoryx work across multiple machines?

No. Iceoryx is designed for single-machine shared memory communication. For cross-machine messaging, pair it with nng or a traditional messaging middleware. The ROS 2 ecosystem demonstrates this pattern: Iceoryx for intra-node, DDS for inter-node communication.

What happens if a process crashes while holding shared memory with Boost.Interprocess?

Boost.Interprocess provides robustness via named_mutex with timed_lock(), but orphaned shared memory segments can persist. Always call shared_memory_object::remove() in a cleanup routine. Consider using RAII wrappers (scoped_lock, remove_on_destroy) and process supervision (systemd, supervisord) to clean up after crashes.

Is nng a drop-in replacement for nanomsg?

Yes, largely. nng is the official successor to nanomsg with a redesigned API that eliminates many foot-guns (state machines, manual timer management). The wire protocols are compatible, so nng can communicate with nanomsg peers. Migration involves replacing nn_socket() with nng_*_open() and nn_recv() with nng_recv().

Does Iceoryx require a separate daemon process?

Yes. The RouDi (Routing and Discovery) daemon manages shared memory allocation and service discovery. It runs as a separate process and must be started before any Iceoryx application. However, it performs no data copying — it only coordinates memory ownership — so it doesn’t add latency to the hot path. RouDi can be configured as a systemd service for production deployment.

Which library is easiest to integrate into an existing CMake project?

nng is the simplest: it’s a C library with a CMake build system and generates nng-config.cmake. Boost.Interprocess requires the Boost headers package. Iceoryx has the most complex build dependency chain (it requires a specific build system with multiple sub-components), but offers a iceoryx_poshConfig.cmake once installed. For quick prototyping, nng takes minutes; Iceoryx may take hours to fully integrate.


💰 想测试你的市场判断力?我用 Polymarket 做预测市场交易——这是全球最大的预测市场平台,从大选结果到技术监管时间线,什么都可以押注。和赌博不同,这是真正的信息市场:你懂的信息越多,胜率越高。我靠预测技术相关事件的走向已经赚了不少。用我的邀请链接注册:Polymarket.com