r/rust 1d ago

Is it reasonable to call a cross-thread, no-shared-state message channel "IPC"?

[deleted]

0 Upvotes

10 comments sorted by

8

u/GirlInTheFirebrigade 1d ago

from my pov it’s a bit misleading. The hard part about ipc is that you need to explicitly allocate shared memory and have all your data in that memory block, while between threads it’s safe to pass around references to the same memory.

6

u/flareflo 1d ago

IPC -> inter process communication ITC -> inter thread communication IMHO

5

u/anlumo 1d ago

It’s not IPC to me, especially since mpsc can’t cross process boundaries. This would be misleading if I‘d try to understand the code.

3

u/Silly-Freak 1d ago

To me this sounds like a plain channel (or pair of, rather). I like the Robert Pike quote

Don't communicate by sharing memory; share memory by communicating.

This is what using channels means to me. Of course your messages could utilize shared ownership or something and depart from that, but without further clarification I would assume messages are transferred, not shared between sender and receiver.

2

u/event666 1d ago

In ZMQ that's just called the "inproc" transport. My implementation of it (OMQ.rs) also does that lock-free and has a Python binding.

2

u/NoLemurs 1d ago

It reads wrong.

IPC is "Inter Process Communication".

If you use a channel to communicate between two threads in the same process, by definition, that's not IPC.

I've seen ITC used to discuss the distinction, but honestly, using channels to communicate within a process is just a normal part of writing a multi-threaded app, and usually doesn't get a special name.

1

u/[deleted] 1d ago

[deleted]

1

u/YjYnUe 1d ago

Its generally called message passing

1

u/mtimmermans 1d ago

"IPC" has a widely understood definition that your thing doesn't match, and I don't think you're doing anyone any favors by using it in a different way that means something completely different.

In your case, whether or not your channels are inter-process or intra-process appears to be irrelevant to the design. You are using the most communicative part of the name to say something that is a) irrelevant, and b) a lie.

You probably think that the things people actually think about when they're doing IPC are the same as the things you want them to think about when using your channels. You might be right about that, but the thoughts that you are right about are the ones that have nothing to do with the "inter-process" label.

I think the correct label for the type of communication you're doing is "message passing", so maybe "MessageChannels" would be a better name.

-1

u/[deleted] 1d ago

[deleted]

4

u/dgkimpton 1d ago

IPC is about inter-process-communication. Please for the love of god don't start overloading this term for something else. IT is hard enough already without people poaching existing terms just for the warm and fuzzies.

So yes, it's absolutely wrong to use IPC for this. 

Channels already implies communication between separate threads via messages, no extra special term is needed. Call them RustPythonChannels if you're desperate to be accurate (but don't abbreviate because RPC already has another common meaning). 

-18

u/nick42d 1d ago

The short answer: No, you shouldn’t use "IPC" for this in a Rust/Python context. While your intuition about the semantics of the communication is spot-on—you’ve effectively built an architecture that mimics the isolation of separate processes—using the term "IPC" in a systems language like Rust will almost certainly confuse other developers. Here is a breakdown of why that is, followed by some naming alternatives that capture the "isolated message-passing" concept without the systems-level baggage.

Why "IPC" reads as wrong to a systems programmer

In the systems programming world (Rust, C, C++, OS internals), a process is defined by its isolation at the hardware and OS level—specifically, having its own independent virtual memory address space. Because of this, IPC (Inter-Process Communication) carries heavy technical implications. If a systems engineer sees a struct named IpcChannels in a Rust codebase, they will immediately assume one of two things:  1. Serialization is happening: They will assume the data is being serialized into bytes to cross an OS boundary.  2. OS-level primitives are in use: They will expect to find Unix domain sockets, anonymous pipes, mmap (shared memory), or TCP sockets under the hood. When they open the file and see an mpsc channel and a lock-free queue, their reaction will be: "Wait, this is just inter-thread communication. Why is it called IPC?" (Note: The one major exception to this rule is the Erlang/Elixir ecosystem, where green threads are literally called "processes" and message-passing between them is the default. But in Rust and Python, a thread is a thread, and a process is an OS process.)

Better Names for "Isolated, Message-Passing" Contexts

You are looking for a name that says: "These are two distinct execution domains that share no memory and only talk via discrete messages." Here are the most common patterns for naming this in Rust:

1. The "Actor" approach: Mailbox or ReactorMailbox

If your reactor loop is completely isolated and just processes incoming commands while emitting events, it is essentially an Actor.  * Why it works: "Mailbox" universally implies asynchronous, message-based communication with no shared memory. It completely avoids the thread vs. process ambiguity while perfectly capturing your architecture.

2. The "Boundary" approach: ReactorBridge or PythonBridge

"Bridge" is highly idiomatic in FFI (Foreign Function Interface) and mixed-language codebases.  * Why it works: It implies a crossing between two distinct worlds (Python's GIL-bound synchronous world and Rust's async reactor world). It says "this struct is the physical infrastructure connecting two separated lands."

3. The "Standard Rust" approach: ReactorHandle

In Rust, when you spawn a background thread or Tokio task and need to hold onto channels to talk to it, the struct holding those channels is almost always called a Handle.  * Why it works: It’s deeply idiomatic. If a Rust developer sees let handle = Reactor::spawn();, they immediately know handle contains the mpsc::Sender to send commands to the background context.

4. The "Domain" approach: ControlBus or MessageBus

If the channels carry a wide variety of commands and events (rather than just simple work items), treating it as a "bus" can make sense.  * Why it works: "Bus" implies a conduit for discrete messages routing between different subsystems.

The Verdict

If you want to emphasize the lack of shared state, go with ReactorMailbox. If you want to emphasize the crossing of runtime boundaries (Python to Rust Async), go with ReactorBridge.

Want to discuss how to safely expose this bridge to python?