Friday 24 February 2012

IsolatedStorage and Thread Safety

In the documentation of the IsolatedStorageFile class, Microsoft say this:

Any instance members are not guaranteed to be thread safe.

Normally, members not being guaranteed to be thread safe means that when you have an object, the object cannot be shared across threads and have members called from more than one thread.

I suspect either that is not what is intended, or there’s a serious bug.

If you’ve followed my two previous posts today, you’ll notice that I’ve been trying to read from IsolatedStorage on a ThreadPool thread, and was debating whether I needed to create a separate IsolatedStorageFile for each thread.

Interepreting the statement in the documentation strictly implies that I should call GetUserStoreForApplication to get a new instance whenever I want to examine isolated storage.

Now, imagine my surprise when I fire up more than one thread pool thread, and get an exception when calling GetFileNames with a set of non-overlapping folders as follows:

System.IO.IsolatedStorage.IsolatedStorageException

An error occurred while accessing IsolatedStorage.at System.IO.IsolatedStorage.IsolatedStorageFile.EnsureStoreIsValid()
at System.IO.IsolatedStorage.IsolatedStorageFile.GetFileNames(String searchPattern)
at App.Model.DaySummary.BackgroundProcess()
at Microsoft.Phone.Reactive.Observable.<>c__DisplayClassa0.<>c__DisplayClassa2.<ToAsync>b__9f()
at Microsoft.Phone.Reactive.ThreadPoolScheduler.<>c__DisplayClass1.<Schedule>b__0(Object _)
at System.Threading.ThreadPool.WorkItem.WaitCallback_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadPool.WorkItem.doWork(Object o)
at System.Threading.Timer.ring()

So it now looks like I need to protect this with some kind of lock to prevent more than one object accessing any aspect of IsolatedStorage at a time.  Adding a lock around the creation of the IsolatedStorage object certainly prevents the error.

Addendum

Well, it looks like I had a bug.  When I rewrote my wrapper class for getting the IsolatedStorageFile via GetUserStoreForApplication, I inadvertently forgot to remove the static keyword from the variable holding it.  As a result, I was using the same object across threads.

In that situation, as you would expect, the object failed, as it is not guaranteed thread safe.  Removing the static keyword is all it took to fix the problem, so for the moment it looks like separate instances can be used at will on a single thread without regard to what else is accessing isolated storage (from a thread safety point anyway).

update March 1 2012

Quite a lot of discussion has happened on the AppHub forums on this since it was originally written, concerning thread safety of the entire platform.

If you’re interested, the whole discussion is here.

No comments:

Post a Comment