I suggest looking at the application and structuring the issues you are confronted with.
Multi-threading
Starting two processes is by far not the biggest issue, as Ziffusion said you can have another process do something else. Plus there are python bindings for C, so you can create another thread for example (no need for it to be a process) and call your python routines from the C program.
Communication
Sharing information is more interesting as you have to solve two issues: one is technically getting the data from one place to another and viceversa; the other is how two different things can work on the same data.
This goes into messaging patterns and process flow:
- who generates the data?
- who receives the data?
- is there a piece of code waiting for something before proceeding?
- is there the need to control what happens to the data while the data is processed?
- do I want to code it myself?
- can I use libraries in the project?
- are there security limitations?
- ...
Once you answer the above questions, you can define how your pieces of the application are going to interact. One main distinction is synchronous vs asynchronous.
Sync vs Async
Synchronous means that for every message there is a reply which should be contained in a time envelope of finite (usually as small as possible) size. This in order to avoid latency.
This a pattern best used when you have to finely control what's happening, or you need an answer to the question in timely manner.
It is, in fact, how http works to download web pages: whenever you load a web site, you want to see the content right now.
This is a pattern called REQuest/REPly
Asynchronous is often used in case of heavy processing: the data producer (for example a a database interface, or a sensor) sends a bulk of data to a worker thread, without waiting for an answer. The worker thread then starts doing its job on the data, and when it's done sends the results to a data sink/user.
This pattern is called PUBlish/SUBscribe.
There are many others, but these form the basics of communication.
Marshalling
Another issue you face is how to structure the data passing, marshalling.
How to get the meaning and content of your data from one context to a totally different one.
For example from your C part to your Python part.
Maintaining serializing libraries is tedious and perilous not to mention prone to backward compatibility issues.
Implementation
When you come to implementation you usually want the cleanest and most powerful code. The two things are clearly against each other. So I usually go look for a library that can do exactly what I need.
In this case my advice is to try ZeroMQ: it is thin, flexible, low-level.
It will give you a powerful framework to interface threads, processes and even machines.
ZeroMQ provides the link, but you still need a protocol to run over this link.
To avoid incredible headaches and streamline your work with respect to the marshaling issue, I suggest you investigate available marshaling libraries that make this task easy.
Cap'n proto, Flatbuffers, Protocol buffers (Google, can't post more than 2 links yet)
They make it easy to define your data in an intermediate language, and parse it from any other language without you having to write all the classes yourself.
As for pipes and shared memory my humble opinion is: forget they exist.