I'm looking for a bit of Win32 help here.
I have a small program that runs in the background, listens for key presses, and automates stuff I don't feel like doing (mostly changing settings and showing notifications). It's mostly just an excuse to practice C++ again and learn more about the Win32 API.
What I want to do is enforce a single instance policy for the program. The twist is I want the surviving process to be the
most recently opened process, not the existing process. This is complicated by the fact that hotkeys can only be registered for once in windows, making this a 'shared resource'.
Now, I've implemented this in a naive way with an event. It works like this:
Process 1
- Starts, creates the event.
- Event didn't already exist, this is the first process.
- RegisterHotkey
- In the message loop wait for input or the event.
Process 2
- Starts, creates the event.
- Event already exists, this is not the first process.
- Signal the event.
- Wait on the event.
Process 1
- Wakes up due to the event.
- UnregisterHotkey
- Signal the event.
- Exit
Process 2
- Wakes up due to the event.
- RegisterHotkey
- In the message loop wait for input or the event.
This
mostly works, but it can fail in a couple places. One, since signalling an already signaled event has no effect, information is lost when two threads signal the event before it gets used. I don't think I managed to get this to happen in practice, but in theory it would lead to one of the threads getting stuck on a wait function. Two, the order in which threads are woken by the event is not strictly FIFO. It's
mostly FIFO, hence the pattern mostly working. This manifests in a few ways, the important one being when a new thread signals the event it may wake a thread that isn't the one that actually owns the hotkeys and that usually leads to no one owning the hotkeys and everyone shutting down, including the newest instance. I'm able to cause the second issue fairly easily by highlighting the exe, holding enter for a few seconds, and waiting for Windows to decide to start waking threads 'out of order'.
I'm looking for suggestions on how to handle this robustly.
I've come up with a couple ideas that I'm fairly certain would work, but they're always complicated, involving 3 forms of synchronization (e.g. mutex for the hotkeys, manual reset event to signal threads to shutdown, and shared memory to know who the newest process is). I'm assuming there's simpler, more clever ways to handle this I've yet to come up with.
Here are my requirements:
- The newest process always wins.
- Solution uses 3 or fewer forms of synchronization.
- OPTIONAL: An older process is notified once for every new process.
(remember, this is an exercise for fun and learning so I don't care that my requirements don't map to some 'real world use case').
The code is here if anyone wants to poke around:
https://github.com/akbyrd/Pigeon
The optional requirement is because I show a notification when a process is superseded and it's fun to watch this happen:
http://i.imgur.com/ApVYTLd.gif