[WP7Dev] Beware of the [ThreadStatic] attribute on Silverlight for Windows Phone 7

By Admin at June 19, 2010 21:36 Tags: , , , , , , ,

Cet article est disponible en francais.

In other words, it is not supported !

And the worst in all this is that you don’t even get warned that it’s not supported... The code compiles, but the attribute has no effect at all ! Granted that you can read the msdn article about the differences between silverlight on Windows and Windows Phone, but well, you may still miss it. Maybe a custom code analysis rule could prevent this.

Still, you want to use ThreadStatic because you probably need it, somehow. But since it is not supported, you could try the Thread.GetNamedDataSlot, mind you.

Well, too bad. It’s not supported either.

That leaves us implementing or own TLS implementation, by hand...

 

Updating Umbrella for Silverlight on Windows Phone

I’m a big fan of Umbrella, and the first time I had to use Dictionary<>.TryGetValue and its magically aweful out parameter in my attempt to rewrite my Remote Control app for Windows Phone 7, I decided to port Umbrella to it. So I could use GetValueOrDefault without rewriting it, again.

I managed to get almost all the desktop unit tests to pass, except for those who emit code, use web features, use xml and binary serializers, call private methods using reflection, and so on.

There are a few parts where the code needed to be updated, because TypeDescriptor class is not available on WP7, you have to crash and burn to see if a value is convertible from one type to the other. But that’s not too bad, it works as expected.

 

Umbrella’s ThreadLocalSource

Umbrella has this nice ThreadLocalSource class that wraps the TLS behavior, and you can easily create a static variable of that type instead of the ThreadStatic static variable.

The Umbrella quick start samples make that kind of use for it :

    ISource<int> threadLocal = new ThreadLocalSource<int>(1);

    int valueOnOtherThread = 0;

    Thread thread = new Thread(() => valueOnOtherThread = threadLocal.Value);
    thread.Start();
    thread.Join();

    Assert.Equal(1, threadLocal.Value);
    Assert.Equal(0, valueOnOtherThread);

The main thread set the value to 1, and the other thread tries to get the same value from the other thread and it should be different (the default value of an int, which is 0).

 

Updating the ThreadLocalSource to avoid the use of ThreadStatic

The TLS in .NET is basically a dictionary of string/object pairs that is attached to each running threads. So, to mimic this, we just need to make a list of all threads that want to store something for themselves and wrap it nicely.

We can create a variable of this type :

    private static Tuple<WeakReference, IDictionary<string, T>>[] _tls;

That variable is intentionally an array to try to make use of memory spacial locality, and since on that platform we won’t get a lot of threads, this should be fine when we got through the array to find one. This approach is trying to be lockless, by using a retry mechanism to update the array. The WeakReference is used to avoid keeping a reference to the thread after it has been terminated.

So, to update the array, we can do as follows :

    private static IDictionary<string, T> GetValuesForThread(Thread thread)
    {
        // Find the TLS for the specified thread
        var query = from entry in _tls

                    // Only get threads that are still alive
                    let t = entry.T.Target as Thread

                    // Get the requested thread
                    where t != null && t == thread
                    select entry.U;

        var localStorage = query.FirstOrDefault();

        if (localStorage == null)
        {
            bool success = false;

            // The storage for the new Thread
            localStorage = new Dictionary<string, T>();

            while(!success)
            {
                // store the original array so we can check later if there has not
                // been anyone that has updated the array at the same time we did
                var originalTls = _tls;

                var newTls = new List<Tuple<WeakReference, IDictionary<string, T>>>();

                // Add the slots for which threads references are still alive
                newTls.AddRange(_tls.Where(t => t.T.IsAlive));

                var newSlot = new Tuple<WeakReference, IDictionary<string, T>>()
                {
                    T = new WeakReference(thread),
                    U = localStorage
                };

                newTls.Add(newSlot);

                // If no other thread has changed the array, replace it.
                success = Interlocked.CompareExchange(ref _tls, newTls.ToArray(), originalTls) != _tls;
            }
        }

        return localStorage;
    }

Instead of the array, another dictionary could be created but I’m not sure of the actual performance improvement that would provide, particularly for very small arrays.

Using a lockless approach like this one will most likely limit the contention around the use of that TLS-like class. There may be, from time to time, computations that are performed multiple times in case of race conditions on the update of the _tls array, but that is completely acceptable. Additionally, livelocks are also out of the picture on that kind of preemptive systems.

I think developing on that platform is going to be fully of little workarounds like this one... This is going to be fun !

Canadian Mobile Data Plans

By Jerome at April 13, 2008 20:06 Tags: ,

I've been interrogating myself a lot lately about the current state of mobile internet in Canada. I'm using my cell phone with a 25$ a month (excluding taxes) data plan for 5 Megabytes, which makes it almost useless for web browsing. Besides, using an HSDPA cell phone, I would deplete my data plan in about 5 minutes.

There's been a lot of buzz around the price of Canada data plans and the absence of the iPhone in Canada for the past year. Projections showed that using an iPhone would cost something like 300$ a month with data plans comparable to what AT&T is offering. I'm guessing that noone would be interested in paying that much to have a 500MB almost unlimited data plan. It seems that Rogers is not willing to let go of the current data plan rates to offer a service that appropriate to the iPhone.

I'm new to the Canadian environment, but for what I can tell when I sometimes hear that Canadians are not really into cell phones -- that they can live without it and do not really need it -- I have an impression of 'déjà vu'. French people had this kind of state of mind when there were only two carriers. People at that time also though they did not need cell phones. Except that it was not that they were technophics, it only was because it was darn too expensive !!

Now, prices in france have dropped a lot, and people are using a lot of services offered by the cell phone carriers. I'm insisting on the services word because I'm sensing that this is where canadians carriers are shooting themselves in the foot by only focusing on being "data pipes". They could expand their business by offering services that would be far more lucrative than only conveying data or voice. If I consider my own use of the voice plan, knowing that the person I am calling is paying the call when he did not initiate the call, makes me talk less.

Ok, there were some improvements the past few months, which Mark is pointing out, but which seem to have halted. Bell released a 7$/month plan which made Canada coming from the most expensive country for data plans to the less expensive in the world, which is a bit odd. With a twist though, it's HTC Touch only. The rest of "improvements" are crippled data plans that are only interesting if you're willing to use the internet that existed 10 years ago...

I'm guessing that breaking the monopoly will change the current state, and that the bidding for new frequencies will force existing carriers to lower their prices to keep their customer base. This is one bit of a stretch, but I'm comparing the state of the industry to the bad phase the music and movie industry is going through right now... There are now forced to understand that they can't sell their music as a product but as a service if they want to keep their business going.

The cell phone industry can be forced to do so to keep their customers, if some newcomer is not playing by the established rules by giving for instance, a flat rate of 45$/month, everything included. I'm not giving this example randomly; I'm referring to the French ISP Free.fr which made quite a perturbation when they offered for something like 45$ a month 100 TV channels, free phone calls to 100 countries in the world, 25Mbps internet, Wifi access point, and a lot more. All this with an excellent quality of service. They did not play by the established rules, and they are now the second most important player in the market and growing every day. I do not see any reason this would not happen for cell phone carriers the same way it did in France.

But maybe there is a good reason for all this though... Canada's a big "empty" space, and maybe expanding the cell coverage is not as money efficient as it is in France, or USA. I don't know all the details, so maybe I'm missing some things.

We'll see in the next few months...

About me

My name is Jerome Laban, I am a Software Architect, C# MVP and .NET enthustiast from Montréal, QC. You will find my blog on this site, where I'm adding my thoughts on current events, or the things I'm working on, such as the Remote Control for Windows Phone.