9

Interesting that this seems to be a basic question, and yet I couldn't find any example of it for the C language (in SO, I found only for Python, C# and C++).

The point is: as a Qt programmer, when I need to make some data to be transmitted between different threads, I start a signal-slot connection between then and use the emit signal mechanism to do the work.

But now I'm working in a C application for Embedded Linux where I need to do a similar work, but I don't have Qt's mechanism available. The question is: how can I make two or more threads communicate with each other in C in a manner similar to that of Qt with signals and slots?

I know that one of the ways to share data is with global variables with changes protected by mutexes. But even then I would probably be unable to do the system in a asynchronous way: I would have to have a loop that would constantly check if the variable has changed or not. But what if I want to execute a specific method of a thread just after another one finished some work (so, in an asynchronous way)? Then it seems such way fails.

Note: although I'm using Embedded Linux and, therefore, mentioning some options that would take POSIX functions and other "Linux-related ways" would be helpful, it would still be better for the community if more time is given to solutions that are not based strictly to one specific platform (if that is possible).

Momergil
  • 2,213
  • 5
  • 29
  • 59

4 Answers4

19

Read a good tutorial on pthreads. You want to know more about condition variables to be used with mutexes.

Condition variables and mutexes should probably be enough for your needs.

You could also use most traditional inter-process communication mechanisms between threads, e.g. a pipe(7) (probably with poll(2)...). So read Advanced Linux Programming and study syscalls(2) and pthreads(7)

Avoid using signal(7)-s between threads and be aware of signal-safety(7). See however signalfd(2), eventfd(2), userfaultfd(2) (you might cleverly handle SIGSEGV with it) and take inspiration from the approach suggested by Calling Qt functions from Unix signal handler.

Observe a running multi-threaded Linux process with strace(1), ltrace(1), gdb(1). You'll understand that several pthreads(7) primitives are using futex(7).

Both GNU glibc and musl-libc are open source and implement the pthreads specification (and Glib, GTK, Qt or POCO are built above them). I invite you to study their source code.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Don't know how `syscalls` fits into this, but otherwise +1. – DarkDust Sep 16 '14 at 19:30
  • They summarize many relevant things for IPC (which can be used between threads): `pipe`, `socket`, `eventfd` etc etc etc ... I don't want to list all the `syscalls` relevant for IPC! – Basile Starynkevitch Sep 16 '14 at 19:31
  • Yeah, but IMHO that's mostly interesting to an advanced developer. I think for a beginner, let's focus on the basics (like mutexes, semaphores and how to use them with `pthreads`; how they are used to coordinate access to shared data; etc.). – DarkDust Sep 16 '14 at 19:36
  • And in 20 years, I have _never_ seen anyone use or even _talk_ about using signals for inter-thread communication?! – DarkDust Sep 16 '14 at 19:37
  • Some questions on SO mentioned that, but I don't recommend using signals for inter-thread communication. – Basile Starynkevitch Sep 16 '14 at 19:38
  • 2
    Since the posted link is broken: https://hpc-tutorials.llnl.gov/posix/ – pawel_winzig Jun 26 '22 at 10:31
5

One way is to use message passing between threads via asynchronous queues. This way you can avoid using shared data between threads and only the queues need to be thread-safe.

Asynchronous queues can be implemented using different synchronisation primitives:

  • Pipes or sockets.
  • Queues protected with a mutex and a condition variable.
  • Non-blocking or lock-free queues.
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
1

Thread which you want to notify of an event like "data available" can register a callback function which can be trigerred by the notifier thread. You can use a function pointer for this.

Ex: Thread 2 registers a callback function for one or more events. Thread 1 on occurrence of the condition or event calls the registered function.

TSP
  • 76
  • 1
  • 6
  • @Basile: Original question is "How to share data with another thread in an async fashion without polling on a global variable". So to achieve this, you can use callback functions which is a general practice in many libraries. – TSP Sep 17 '14 at 04:21
  • Register a callback function with what, please? Which API? – Maxim Egorushkin Sep 17 '14 at 21:11
  • You have to make your own API to do this. It is nothing but a function pointer. – TSP Sep 18 '14 at 01:21
  • Wait, so is it an API, or just a function pointer? How is this thread safe? – Ralph Nov 10 '16 at 13:52
0

producer and consumer threads should capture each other's tid. producer on producing can send: pthread_kill(consumerID, SIGUSR1); consumer is setup with the signal handler for SIGUSR1, and can retrieve the produced result from the common std::queue saved by pthread_setspecific(). producer and consumer can continue their tasks without being locked by semaphore or cond var/mutex.