Archive for April 2006

Tablet PC Programming Articles: Gaming and Smart Clients

Lang.NET Conference: Seattle, Here I Come!

Microsoft is hosting the The .NET Programming Languages And Compilers Symposium in August. 10 minute lightning talks on type systems, domain-specific languages, and code generation? Oh, you know I’m going.

Continuations in Mono: Good News for Language Implementors

According to Miguel de Icaza, Mono, the cross-platform implementation of the .NET CLR, now has continuations thanks to the work of Tomi Valkeinen. The work is here. Continuations are significant to a number of programming languages that have been hard to implement on the CLR. Valkeinen’s work may help a number of compiler developers.

Games on Rails

So, I have the opportunity to help design a game SDK. On the one hand, I can go “sprites, sounds, physics,” etc. And on the other hand, I can say Ruby on Rails. Which is to say, I can look to RoR as an inspiration of a very successful framework. What does Rails tell us about designing frameworks and SDKs and how can it be applied to the domain of “casual games”?

Virtual methods are thread unsafe

In my February 15th SD Times column on the future of concurrent programming models, I wrote “[A] basic rule for thread safety is ‘either write objects with no fields or write objects with no virtual method calls’….” I received an email today from someone asking about why virtual method calls are unsafe. Here’s an excerpt from my book:

Creating a safe multithreaded library is considerably more difficult than creating a single multithreaded application. Not only do you have to try to avoid deadlock in all the scenarios in which your library is used logically, you must never expose a virtual method that is called within a critical section. The problem is that if you declare a method as virtual and call it within a critical section (that is, a section in which you’ve acquired a Monitor), it is possible that the client programmer will override it in a way that creates a new thread and attempts to acquire the same Monitor. For this deadlock scenario to play out, the client must create a new thread since, as discussed on page 753, a call to acquire the Monitor within the same thread’s call stack will succeed. This is a subtle-enough requirement that this object-oriented deadlock can sneak by a lot of unit tests and code reviews.

The injunction goes against all virtual calls: those marked virtual, interfaces, abstract classes, and delegate calls are all vulnerable to this object-oriented deadlocking. In the following program, a Library object executes the method Client.VirtualCall( ). This works alright for FineClient, but BadClient deadlocks:

//VirtualCritical.cs

//Never expose a virtual method inside a lock

using System;

using System.Threading;

using System.Collections;

 

class Library {

  Client client;

  public Client MyClient{

    set { client = value;}

  }

 

  Thread t;

 

  public void Run(){

    ThreadStart ts = new ThreadStart(ThreadCaller);

    t = new Thread(ts);

    t.Name = “Library thread”;

    t.Start();

  }

 

  public void Stop(){

    t.Abort();

    t.Join();

  }

 

  void ThreadCaller(){

    while (true) {

      Console.WriteLine(Thread.CurrentThread.Name +

        ” asking for lock”);

      lock(this){

        Console.WriteLine(Thread.CurrentThread.Name +

          ” acquired lock”);

        client.VirtualCall();

        Thread.Sleep(1000);

      }

      Console.WriteLine(Thread.CurrentThread.Name +

        ” released lock”);

    }

  }

}

 

abstract class Client{

  public abstract void VirtualCall();

 

  Library l;

  public Library Library{

    set { l = value;}

  }

 

  protected bool callDone = false;

 

  public void LockAndTalk(){

    callDone = false;

    while (callDone == false) {

      Console.WriteLine(this.GetType() +

        ” asking for lock”);

      lock(l){

        Console.WriteLine(Thread.CurrentThread.Name +

          ” acquired lock”);

        Console.WriteLine(“Virtual call executed”);

        Thread.Sleep(1000);

        callDone = true;

      }

    }

    Console.WriteLine(Thread.CurrentThread.Name +

      ” released lock”);

  }

}

 

class FineClient: Client {

  public override void VirtualCall(){

    LockAndTalk();

  }

}

 

class BadClient: Client {

  public override void VirtualCall(){

    ThreadedLockAndTalk();

  }

 

  public void ThreadedLockAndTalk(){

    ThreadStart ts = new ThreadStart(LockAndTalk);

    Thread t = new Thread(ts);

    t.Name = “BadClient”;

    t.IsBackground = true;

    t.Start();

    while (callDone == false) {

      Thread.Sleep(1000);

    }

  }

}

 

class TestingClass {

  Library l;

  TestingClass(Client c){

    Console.WriteLine(“Testing ” + c.GetType());

    l = new Library();

    l.MyClient = c;

    c.Library = l;

    l.Run();

 

    Thread.Sleep(10000);

    Console.WriteLine(“Ending test now…”);

    l.Stop();

  }

 

  public static void Main(){

    new TestingClass(new FineClient());

    new TestingClass(new BadClient());

   

  }

}

 

The Library class contains a reference to a Client object, whose VirtualCall( ) method is called within a lock block inside of Library.ThreadCaller( ). The two methods Library.Run( ) and Library.Stop( ) use previously discussed techniques to begin and end the ThreadCaller( ) loop.

In addition to the abstract method VirtualCall( ), the abstract class Client specifies a method called LockAndTalk( ), which acquires a lock on the Library object, outputs something to the screen, waits a second, and then releases the lock. (This violates our preference to lock(this), but it’s the easiest code to demonstrate the danger of virtual method calls.)

FineClient just calls LockAndTalk( ). When LockAndTalk( ) is called in FineClient, it is being executed in the same thread that executed Library.ThreadCaller( ) and that owns the Library monitor. Therefore, FineClient( ) works just fine.

BadClient( ) implements VirtualCall( ) in a way that the Library author did not anticipate: it starts a new Thread whose ThreadStart( ) delegate, a method called ThreadedLockAndTalk( ), calls LockAndTalk( ) from within a new thread. Notice that there is no explicit attempt on the part of the BadClient programmer to lock anything; the BadClient programmer is not doing anything obviously prone to failure. However, when ThreadedLockAndTalk( ) calls LockAndTalk( ) and that method attempts to acquire the lock on the Library object, the lock attempt is being executed from a different thread than the original thread in Library.ThreadCaller( ), which of course already has the lock on the Library object. The result is that although the BadClient programmer has done nothing obviously wrong, the Library deadlocks.

Writing a multithreaded library that is reentrant, that is, can be safely invoked from multiple threads, concurrently, and in a nested manner, is difficult enough at the best of times, but it is much harder if your library makes a virtual method call while holding onto a lock. Critical sections must be as controlled as possible; a virtual method call cedes that control and makes disaster all too likely.

 >

Sudoku source code available on MSDN

Source code for Sudoku game like that in the Microsoft Touch Pack for UMPCs has been released on MSDN.

"This article closely examines Stephen Toub’s Tablet PC-based implementation of Sudoku. It is the same implementation in the Touch Pack, a software package that comes preinstalled on ultra-mobile PCs (UMPCs). The article details the algorithmic aspects of implementing a Sudoku game, in addition to the specific details that help you implement other applications designed for Tablet PC and UMPC."

…And don’t forget the Hexoduko challenge, with a prize of $200 in programming books…

Breast cancer and taxes

Instead of blogging about what’s really going on in my life, I’ll just say that I’m always surprised at the amount of whining I hear from computer professionals about doing taxes. Not whining about taxes, which is more than understandable, especially for the self-employed, but whining about doing taxes. Doing taxes takes me less than a workday and a good portion of that day is very mechanical double-checking of line items and categories.

The key to efficient taxes is tracking expenses during the year. As far as I’m concerned, there are only two keys to making tax preparation trivial:

  1. Use Quicken / Money all year round
  2. Keep and use a separate credit card for tax-related expenditures.

Both Quicken and Money allow you to assign tax-lines to specific categories. Every time you balance your accounts, you just assign the expenditures to the proper line-item (I also have a “Tax:Perhaps” category for ones that I’ll eventually check). And it’s not like it’s that hard to figure out what is and isn’t deductible — business expenses, yes; movie tickets, no. The things that are hard to figure are the mixed-use things: computers, cell phones, home office. To make that easy, I just draw the boundaries in bold red lines: I have a home computer and my business computers, a business cell phone, and my office is all business.

I’ve only had a tax pro do my taxes one year and he gave me a list of questions and forms to fill out and it was at least as hard as using TurboTax.

Maybe preparing taxes is harder if you’re rich.

Functional vs. OOP

Something I’ve been finding myself doing:

 

class Foo{

  int someState;

 

  static int Bar(int state)

  {

    return state * state;

  }

 

  public int Bar()

  {

    return Foo.Bar(someState);

  }

}

 

Essentially, developing my code in a functional manner (easier for unit-testing) and then refactoring a simpler public interface. Waddya’ think?

“Meltdown expected”? Fetch me my cattle prod!

A cab rider was detained for singing along to the Clash song “London Calling.” Geez, lucky he wasn’t singing “Guns of Brixton

Gawd. I am so happy I’m not a teenager today. Given the bands I liked, I’d probably be in Guantanamo by now. I know that some of the stuff I wrote would have got me expelled.

I’ve always felt fortunate that I wasn’t caught doing a bunch of stuff I did as a teenager, because instead of just working things out and becoming a pretty darn mellow guy, I know that it would have been like hooking a fish and I just would have rebelled much more … well, I dare not say “violently” or “extremely” lest I risk extraordinary rendition … so let’s just say that I would have been even more of an insufferable know-it-all rebellious teenager.

I mean, I was just mad at Reagan and nonsense like missile defense, invading Grenada, and supply-side economics. Small beans compared to today’s hypocrisy, corruption, value destruction, and delusional foreign policy.

Crossing the Chasm: Programming Languages Edition

Geoffrey Moore’s Crossing the Chasm is the best explanatory text of why tools succeed in the software development world (its scope is broader than SD, but SD is smack in the middle of its explanatory power). The basic idea is that dividing the world into a bell curve of innovators, early adopters, early majority, late majority, and laggards is useful, but misses a crucial "chasm" that exists between early adopters and early majority:

The gap exists for many reasons, but the major one is that what innovators and early adopters value and expect (with development tools, such things as expressiveness and high productivity but at the cost of learning something new) differs from what the majority values and expects (ease of use, integration). Java crossed the chasm, Smalltalk didn’t.

 

Will Ruby? Well, it’s going to be a challenge. If my theory is right, the “rapid inflation” that Ruby is currently undergoing is indicative that it’s broken out of “innovators” and is in the “early adopters” phase. So “the chasm” is looming. Right now, Ruby doesn’t have the toolset to appeal to early majority and, equally importantly, the Ruby community does not currently “speak to” the concerns of the majority (“Who else is using this?” “What about my existing investments?” “You mean, I have to train everyone in a new language and standard library?”).  A huge problem in terms of “the chasm” is that Ruby interoperability with the CLR and the JVM is “early adopter”-style via bridges/interop. That’s not going to cut it with the majority – if it’s not integrated into Visual Studio or Eclipse, with full Intellisense, it’s not going to make it across the chasm.

 

This is one reason why I think there’s such a golden opportunty for “DevCo” – the ex-Borland languages division — with Ruby. “DevCo” has expertise with “majority” issues: IDEs, integration, support, databases, etc.