views:

109

answers:

1

I'm trying to figure out the best way to manage multiple forms in a C# application that uses dual-monitors. The application starts to a "launchpad," which just gives the operator some quick information and a "GO" button. Pressing that button hides the launchpad and displays a form on each monitor in full-screen. I've tried to capture the relevant code here:

private static List<Thread> _displays = new List<Thread>();

// "GO" button handler
private void OnClick(Object sender, EventArgs args) {
    Launch(new Form1());
    Launch(new Form2());
    WaitForAllDisplays();
}

private static void Launch(Form form) {
    Thread thread = new Thread(LaunchDisplay);
    thread.IsBackground = true;
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start(form);
    _displays.Add(thread);
}

private static void LaunchDisplay(Object obj) {
    Form display = obj as Form;
    // [snip] logic to place form on correct monitor [/snip]
    display.ShowDialog();
}

public static void WaitForAllDisplays() {
    foreach (Thread thread in _displays) {
        thread.Join();
    }
}

It feels a little messy to leave the main thread blocked on this WaitForAllDisplays() call, but I haven't been able to think of a better way to do this. Notice that Form1 and Form2 are independent of each other and never communicate directly.

I considered using a counting semaphore to wait for all displays to close, but this is a little opposite of a traditional semaphore. Instead of executing when a resource becomes available, I want to block until all resources are returned.

Any thoughts on a better approach?

+1  A: 

At first I thought of this would work:

You can use Events for example: 2 ManualResetEvent objects. The main thread will wait on the events using WaitHandle.WaitAll and an array of 2 Mutexes. Each thread gets a reference to 1 event and signals it when it's done (before it dies).

But then I figured you're better off using 2 mutexes instead and waiting on them. This way if a thread is terminated abnormally without "signalling" (=Releasing the mutex) you'll get a AbandonedMutexException which you can and should handle. You can use AbandonedMutexException.MutexIndex to know which thread caused the exception.

You can have a look at this answer to see how to handle the mutex and exception

NOTE:

  1. AbandonedMutexException is new in the .NET Framework version 2.0. In previous versions, the WaitAll method returns true when a mutex is abandoned. An abandoned mutex indicates a serious coding error. The exception contains information useful for debugging.
  2. This exception is not thrown on Windows 98 or Windows Millennium Edition.
dtroy
This is a good approach for handling my mutex problem... I ended up subscribing to the `FormClosing` events and just keeping a counter of "open dialogs." I was able to eliminate the need for the `WaitForAllDisplays()` method. Thanks for the suggestions!
jheddings