,

Using a Mutex to Access Common Resources Safely

Your app’s task agent may be invoked even when your app is in the foreground. It is, therefore, important to ensure that simultaneous access to shared resources, such as files in isolated storage, is controlled and performed safely.

A System.Threading.Mutex can be employed to synchronize critical sections of code—code that accesses a common resource—within your primary app and your background agent. A Mutex is a synchronization primitive. It is similar to the Monitor class, but with a scope that allows you to achieve interprocess synchronization, enabling you to synchronize across your foreground app and your background agent.

Unlike Silverlight for the browser, a Mutex instance in Windows Phone must be named, and the scope of a Mutex is limited to your primary app and its background agent.


Note

A Mutex cannot be used to synchronize different apps, nor as a conduit for interapp communication.


Listing 32.11 shows an excerpt from the CommonResourceExample class in the downloadable sample code that demonstrates how to read and write to a file in isolated storage in a safe manner, while preventing another thread, such as from your background agent, from accessing the file simultaneously.

When the ReplaceFileContents method is called, WaitOne is called on the Mutex, which blocks if the Mutex is owned by another thread in your foreground app or a background agent. If not owned, or when released by another thread, the contents of a file are read, and then overwritten with a new content string. The result is returned to the caller. By using a Mutex, the result is guaranteed to be the content of the file immediately prior to writing the new content.

LISTING 32.11. CommonResourceExample Class (excerpt)


public class CommonResourceExample
{
    static readonly Mutex mutex = new Mutex(false, "CommonResourceExample");
    static readonly string fileName = "CommonResourceExample.txt";

    public string ReplaceFileContents(string fileContent)
    {
        try
        {
            mutex.WaitOne();
            string result = ReadFileCore();
            WriteFileCore(fileContent);
            return result;
        }
        finally
        {
            mutex.ReleaseMutex();
        }
    }
    void WriteFileCore(string fileContent)
    {
        using (IsolatedStorageFile isolatedStorageFile
                        = IsolatedStorageFile.GetUserStoreForApplication())
        {
            using (IsolatedStorageFileStream outStream
                        = isolatedStorageFile.OpenFile(
                                 fileName, FileMode.Create))
            {
                using (StreamWriter writer = new StreamWriter(outStream))
                {
                    writer.Write(fileContent);
                }
            }
        }
    }

    string ReadFileCore()
    {
        using (IsolatedStorageFile isolatedStorageFile
                    = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (!isolatedStorageFile.FileExists(fileName))
            {
                return string.Empty;
            }

            using (IsolatedStorageFileStream inStream
                        = isolatedStorageFile.OpenFile(
                               fileName, FileMode.Open))
            {
                using (StreamReader reader = new StreamReader(inStream))
                {
                    return reader.ReadToEnd();
                }
            }
        }
    }
}


It is important to ensure that your Mutex is released upon exiting from a critical section. This is done by wrapping the section in a try/finally block. If your foreground app or your background agent terminates while owning a mutex, the state of the mutex is set to signaled and the next waiting thread gets ownership.

To test whether the Mutex is owned, you can specify a timeout parameter to the WaitOne method (see Listing 32.12). This is an effective way to prevent your task agent from being terminated because it is blocked on a WaitOne call. Recall that a PeriodicTask has a maximum 15 seconds of execution time.

LISTING 32.12. Using WaitOne to Determine Whether a Mutex Is Owned


bool mutexAcquired = false;
try
{
    mutexAcquired = mutex.WaitOne(10000);
    if (mutexAcquired)
    {
        /* Access common resource here. */
        Debug.WriteLine("mutex entered.");
    }
}
finally
{
    if (mutexAcquired)
    {
        mutex.ReleaseMutex();
    }
}

if (!mutexAcquired)
{
    /* Unable to acquire ownership of mutex. */
    Debug.WriteLine("mutex timed out.");
}



Tip

To test whether a Mutex is owned, without blocking the calling thread, use a timeout value of 0 when calling WaitOne.


Mutex provides an effective way to synchronize critical sections of code and can assist in avoiding race conditions and other concurrency issues when accessing shared resources.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.198.138