Thread synchronization is not a new topic, however there are times we might be faced with use-cases beyond just controlling access to a shared resource. One of such use-cases I encountered a while ago was being able to coordinate interaction between different threads across multiple processes using a signaling construct in C#.
A process is a single instance of your app in memory. Processes run in parallel within a computer/server, fully isolated from each other and can have multiple threads - each running in parallel only within that process and have just a limited degree of isolation. In multi-threading, each thread will have its own independent stack but will share the heap memory with other threads within the same process.
On the web
With HTTP being a connection-less and stateless protocol - each new request to your service will spawn a new thread and after the request is serviced, the connection is lost and resources released. A new connection must be made for each request - fully isolated from each other.
Now imagine for instance, you have an app that triggers a third party identity service when a user tries to log in, but the service doesn't give responses - it only triggers a webhook telling you whether to proceed or not.
To login, the user makes a login request with her login credentials, - this is one request on your server, seen as a single thread, your app makes a request to the identity service, the service retrieves the fingerprint id and makes a request to your webhook - this is a separate request to your server, seen as another thread completely isolated from all other threads. There will be no way for the login request to know when the webhook has gotten a response and how to proceed. The login request might end before the webhook even gets a response.
It gets trickier! Lets say, you need to scale your app across multiple nodes/instances/replicas - in this case, each new request might spawn an entirely new process with its own threads. Say you have a 3 load-balanced nodes, the login request might be serviced by node 1 and the webhook serviced by node 3 - totally disjoint and isolated from each other.
This is where Thread interaction/signalling comes in. Typically, you want the user login request to stay alive and wait until the webhook gets a response. There should be a mechanism where the webhook [request/thread] signals the login request - "Hey, i'm here, all set, you can respond to customer now"
Yes, you can work around this by creating artificial synchronization using persistent constructs like lock files and databases, but these are very bad designs - both architecture, resource and performance wise. You just might see why when implementing a batch processing master-worker queue or something of that sort.
There is a simple way to achieve this in C# using EventWaitHandle to allow threads to communicate with each other by signaling. Signaling is when one thread waits until it receives notification from another. Using a Mutex or a Semaphore does not just cut it... (more on this later). Typically, one or more threads block on an EventWaitHandle until an unblocked thread calls the Set method, releasing one or more of the blocked threads. These threads should have unique names so that a different thread from another process can send the right signal.
At the webhook end, when a response is received, all you need do is call Set() on the named thread and it will be released.
EventWaitHandle eventReleaser =
new EventWaitHandle(false, EventResetMode.AutoReset, "user_username");
There is a caveat; The thread lock was behaving like a Mutex in Linux (locking the entire process, so your entire app can't respond to requests). I discovered that named threads were not supported in Unix* system because of the underlying arch.
Most batch processing task are run out of process - using cronjobs, schedulers or other system specific batch processing services. This is encouraged for heavy weight processing but take a simple url scrapper for example or some system that required linear batch processing in a producer/consumer manner. If you are using multiple threads to perform the work, then you need a way to harmonize the order they are executed in.