UnclePaul
UnclePaul

Reputation: 515

Windows Phone 7.1 application quits without throwing any exception

Currently working on a multi-threaded WP 7.1.1 application and slightly more than half of the time the application quits during the "initial phase" without throwing any Exception. It simply ends with all threads returning 0x0 and without entering any Closing/Exit/Quit events.

...
The thread '<No Name>' (0xfde00d2) has exited with code 0 (0x0).
The thread '<No Name>' (0xe860116) has exited with code 0 (0x0).
The thread '<No Name>' (0xfdf00c6) has exited with code 0 (0x0).
The thread '<No Name>' (0xf8d012e) has exited with code 0 (0x0).
The thread '<No Name>' (0xfd5010e) has exited with code 0 (0x0).
The thread '<No Name>' (0xfbc011a) has exited with code 0 (0x0).
The thread '<No Name>' (0xf9900ee) has exited with code 0 (0x0).
The program '[268042506] UI Task: Managed' has exited with code 0 (0x0).
EOL 

What does "initial phase" mean exactly? I profiled the app with "Windows Phone Performance Analysis" and together with some debug messages and some logging I estimate it is approximately 3-4 seconds after the start. At his point the GUI is already visible for a very brief amount of time.

I'm almost certain that the problem occurs duo to the following call:

private static List<MyEntries> EntriesLoad()
{
    using(var context = Context.ReadOnly) // <- works
    {
        return context.MyEntries.Where(m => !m.Deleted).OrderBy(m => m.Name).ToList(); // <- problem
    }
}

private async void EntriesReload()
{
    EntriesLoaded = false; // <- called
    var entries = await TaskEx.Run<List<MyEntries>>(EntriesLoad); // <- called
    EntriesLoaded = true; // <- only get's called 50% of the time/ otherwise app quits
}

To prevent any multithreading issues with the DataContext, a new context is created on each call:

public static Context ReadOnly 
{
    get { return new Context(ConnectionReadOnly); }
}

I even tried BackgroundWorker and ThreadPool instead of the Async CTP 3, but with the same effect. I know very similiar questions have been been asked many times before, but I simply couldn't find any solution as of yet to my problem. Is there any way/ program I could find the exact method (reason, loc) that is causing the exception? Are there maybe any limits on how many threads can be created? Can DataContext be safely used in this manner?

Your help is much appreciated.

Upvotes: 1

Views: 592

Answers (2)

UnclePaul
UnclePaul

Reputation: 515

Thank you Stephen for you reply. I was still unable to catch any exception with your proposed changes, however, your answer helped me to better understand what is going on behind the curtain. So thanks again for that.

I finally managed to get rid of all the "silent" exceptions that caused the application to - almost half the time - quit randomly shortly after the start. To my surprise it was perhaps not caused by any code of mine, but could be originated in the DataContext class. How come? In my application I have been using two different connection strings:

/* with DeferredLoadingEnabled = false; ObjectTrackingEnabled = true; */
private const string Connection = "Data Source=isostore:/MyDatabase.sdf;max buffer size=1024;max database size=512;";

/* with DeferredLoadingEnabled = false; ObjectTrackingEnabled = false; */
private const string ConnectionReadOnly = Connection + "File Mode = read only;";

The exceptions only occured during (and not after, before or while assigning return values) read opperations on a DataContext that used the ReadOnly connection string. Getting rid of the ReadOnly property, and not changing a single other line of code, solved my problems completely. So maybe there is a threading issue in DataContext or in one of the libraries? I can't really judge the performance impact of abstaining from ReadOnly connections, but since I'm only retrieving a small amount of data and I'm using DataContext in a very atomic-manner, I don't mind a possible overhead in my particular use case.

Upvotes: 0

Stephen Cleary
Stephen Cleary

Reputation: 456677

When an async void method throws an exception, that exception is passed straight through to the "context" - in this case, a UI context.

So - even if you're calling EntriesReload in a try/catch - you'll never catch any exception raised by EntriesReload.

async methods should always return Task or Task<TResult>, unless they have to return void (e.g., async event handlers).

Then when you call EntriesReload, await the result. This will not fix the crash, but it'll let you see the exception.

Upvotes: 2

Related Questions