August 2012 3 posts
Synchronization in async C# methods
Wednesday, August 29, 2012
The C# keyword async
allows one to write synchronous-looking asynchronous code. While very convenient, sometimes there are non-obvious pitfalls.
Suppose in an async
method, we want to await
something while holding a lock. An example might be a critical section where two network requests should never be made concurrently. The following results in a compile-time error because you cannot use await
inside a lock
block:
lock (foo) { await Task.Delay(1); }
(Task.Delay(n)
is a Task
that does nothing and completes after n milliseconds. I'm using it here as a convenient example of an asynchronous operation.)
You may think to use System.Threading.Mutex
:
private Mutex mutex = new Mutex(); public async Task DoSomethingAsync() { mutex.WaitOne(); await Task.Delay(1); mutex.ReleaseMutex(); }
The catch here is that many, but not all, await
ed methods will resume execution on a different thread than the calling thread. In the example above, Task.Delay(n)
resumes on a different thread whenever n > 0, so the thread that attempts to release the Mutex
will be different than the one which acquired it. Because a Mutex
must only be released by the same thread that acquired it, the following exception will be thrown:
System.ApplicationException: Object synchronization method was called from an unsynchronized block of code.
However, you can just use System.Threading.Semaphore
to do the same thing, since these aren't bound to any particular thread:
private Semaphore semaphore = new Semaphore(1, 1); public async Task DoSomethingAsync() { semaphore.WaitOne(); await Task.Delay(1); semaphore.Release(); }
Of course, if you are holding synchronization objects for long periods of time as implied by the await
keyword, it may be worth rethinking the design to avoid this issue and the inevitable blocking of threads during long asynchronous operations.
Parsing URI query strings in Windows 8 metro-style apps
Tuesday, August 21, 2012
Take the URL string http://example.com/?a=foo&b=bar&c=baz
. How do we parse its query parameters using C# to get a dictionary or other key-value data structure?
In .NET, you can use HttpUtility.ParseQueryString(), but that function isn't present in WinRT APIs. Fortunately, there is a replacement: WwwFormUrlDecoder. The code below demonstrates its capabilities:
using System; using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; using Windows.Foundation; [TestClass] public class Tests { [TestMethod] public void TestWwwFormUrlDecoder() { Uri uri = new Uri("http://example.com/?a=foo&b=bar&c=baz"); WwwFormUrlDecoder decoder = new WwwFormUrlDecoder(uri.Query); // named parameters Assert.AreEqual("foo", decoder.GetFirstValueByName("a")); // named parameter that doesn't exist Assert.ThrowsException<ArgumentException>(() => { decoder.GetFirstValueByName("not_present"); }); // number of parameters Assert.AreEqual(3, decoder.Count); // ordered parameters Assert.AreEqual("b", decoder[1].Name); Assert.AreEqual("bar", decoder[1].Value); // ordered parameter that doesn't exist Assert.ThrowsException<ArgumentException>(() => { IWwwFormUrlDecoderEntry notPresent = decoder[3]; }); } }
Writing a Windows 8 Metro Hello World app using C#, XAML, and calling into a C++ component
Sunday, August 5, 2012
Windows 8 and the new WinRT promises fluid interoperability between C#, C++, and HTML/Javascript. Today we'll take a quick look at a Hello World app built using C# and XAML calling into a C++ component.
First, create a new blank C#/XAML app and call it HelloInterop:
Next, add a new project to this solution:
Choose the C++ Windows Runtime Component project type and call it HelloCpp.
Finally, right click on the C# HelloInterop project in the Solution Explorer and choose "Add Reference..." then add the C++ component as a reference (you may have to choose "Solution" on the left pane first):
Now, we'll work on the C++ code. Open up Class1.h
. (Feel free to rename it, but for this guide we'll just stick with this name.) Notice that it's a public ref class
and is contained within a namespace
— this is required if this class is to be visible to external consumers. Let's add a simple function. Add this line under the constructor's declaration:
Platform::String^ ConcatString(Platform::String^ a, Platform::String^ b);
Now open Class1.cpp
and implement this function by adding this code to the bottom of the file:
String^ Class1::ConcatString(String^ a, String^ b) { return String::Concat(a, b); }
To make the app call this function, let's add a TextBlock
to the main page. Open MainPage.xaml
and add this line to the page inside the Grid
:
<TextBlock Name="CppTextBlock"/>
In MainPage.xaml.cs
, add some code inside OnNavigatedTo()
to set the text of this element:
var c = new HelloCpp.Class1(); this.CppTextBlock.Text = c.ConcatString("Hello ", "World");
Now run the app and you should see "Hello World" on your screen.