EDIT: Please read the comments as well, as they make some good suggestions.
I learned a few things yesterday, which I think are worth sharing. Perhaps eventually I will write this up as an article, rather than just a post.
Anyway, with Todo 3.0 I don’t want users having more than copy of Todo open at one time. If a user makes changes in one instance of the program, and it saves it, then the user makes changes in the other instance of Todo, the changes made in the second instance will overwrite any changes made in the first instance. The end result is a confused user who is wondering why tasks on thier todo list weren’t saved.
The way to go about fixing this is to prevent the user from opening more than one copy of Todo. There are a couple ways this could be done – you could open up a file when you first start your program, and keep it open until you close your program. If, when you start up your program, you aren’t able to open the file because it is already opened by another program, you let the user know that there is another instance of your program running. For the most part, this does work. So why not use it? Well, having a file open is a waste of resources. That, and there is a better way.
In the world of multi-threaded programming there is something called a mutex. It’s basically restricts access to a particular part of your program to a single thread, and forces any other threads to wait until that part of the program is complete. This comes in handy for synching things between threads. This can also be used to ensure that only one instance of your program is running. Here’s some code snippets straight from Todo 3.0:
In your main C# form, declare a mutex:
private Mutex mutex;
private string mutexName = "Todo3.0Mutex";
Then, in your form constructor, you want to do the following:
//before anything else happens, check for an existing mutex with the same name. If there is a mutex
//with the same name, that means there is already one copy of Todo 3.0 open, so let the user know
//what is going on, and kill this one
mutex = Mutex.OpenExisting(mutexName);
//since it hasn't thrown an exception, then we already have one copy of the app open.
MessageBox.Show("A copy of Todo 3.0 is already open. Please check your system tray (notification area).",
"Todo 3.0", MessageBoxButtons.OK, MessageBoxIcon.Information);
catch (Exception Ex)
//since we didn't find a mutex with that name, create one
Debug.WriteLine("Exception thrown:" + Ex.Message + " Creating a new mutex...");
mutex = new Mutex(true, mutexName);
So, now you have a named mutex, and you have ensured that only one instance of your program is open. There is only one thing left to do – when you exit your program you need to be sure to release the mutex:
Now you may have noticed something strange – in the constructor, after I check for a named mutex, and I find one, I let the user know that there is already one instance of the progam open, then I call:
Why do I do this? Because of the structure of how the Windows Forms messages are handled, if I were to call Application.Exit(), it wouldn’t work. Application.Run() needs to be called first in order for Application.Exit() to work, which hasn’t happened yet because we are only in the constructor. There is probably a better/safer way to do this, but I haven’t figured it out yet and this seems to be working fine in the mean time.
Technically, rather than using mutexes (or mutices? What is the plural of mutex?), I could have used Semaphores. A Semaphore is similar to a mutex, but rather than restricting access to only a single thread, it can set a limit to the number of threads that can access a resource. For example, we could limit access to a particular resource to 3 threads. In our case, we only need one thread to access things, so it’s probably a bit more kosher to use a mutex.
If I am completely wrong about something in this post, let me know. My understanding of multi-threaded programming is very limited. Either way, I thought this was pretty cool, and I figured some of you other folks out there might be interested in seeing this.
(Sorry for the borked code – it should be nicely tabbed, but the code tags don’t seem to like that. Oh well).