Thursday, May 21, 2009

Parallel Programming with .NET : Samples for Parallel Programming with the .NET Framework 4

Now that .NET Framework 4 is out, we start seeing new samples.

Parallel Programming with .NET : Samples for Parallel Programming with the .NET Framework 4

Monday, May 18, 2009

Visual Studio 2010 beta 1 is available

Finally Visual Studio 2010 Beta 1 is available. I was waiting for that release for so long. I’m eager to test my Parallel Extensions demo on it.

http://msdn.microsoft.com/en-ca/subscriptions/downloads/default.aspx?pv=18:370

Stay tuned I will tell you how it goes.

Wednesday, May 13, 2009

How to test your multi-threaded code (part 3 of 3)?

In the last post we learned how to find and fix a simple multi-thread problem. Now we will see a more complex scenario and see how CHESS wil find the solution.

To do that we will add a ne method to our Account type.

public static void Transfer(double amount, Account fromAccount, Account toAccount)
{
    lock (fromAccount)
    {
        lock(toAccount)
        {
            fromAccount.Withdraw(amount);
            toAccount.Deposit(amount);
        }
    }
}

Because we want to be sure that the transfer works we lock both the “from” and the “to” account.

Now we can easily wrtie this test to see that this is working fine in signle threaded scenario.

[TestMethod]
public void TransferTest()
{
    Account a1 = Account.OpenNew(10000);
    Account a2 = Account.OpenNew(10000);

    Account.Transfer(100, a1, a2);
    Account.Transfer(100, a2, a1);

    Assert.AreEqual(10000, a1.Balance);
    Assert.AreEqual(10000, a2.Balance);
}

As we did before we will convert this single-thread method to a multi-thread one.

[TestMethod]
[HostType("Chess")]
public void TransferMultiThreadTest()
{
    Account a1 = Account.OpenNew(10000);
    Account a2 = Account.OpenNew(10000);

    Thread thread = 
new Thread(o => Account.Transfer(100, ((Account[]) o)[0], ((Account[]) o)[1])); thread.Start(new[] {a1, a2}); Account.Transfer(100, a2, a1); thread.Join(); Assert.AreEqual(10000, a1.Balance); Assert.AreEqual(10000, a2.Balance); }

Now if we run this CHESS will detect a deadlock scenario. If you’ve done some SQL queries you know you should always try to lock all your resources always in the same order. But why doesn’t it working here. We have only one method that lock resources they should be locked in the same order every time, and that’s true. The deadlock occurs because in some cases a thread start to lock the fromAccount (or maybe the toAccount too) and get interrupt by another thread trying to do the same. Then both thread are waiting for each other to complete. Databases engine use timeouts to get out of these situation, but the lock keyword doesn’t support timeout, eventough it uses Monitor.Enter which support it. In another post I will show you how to build your own lock implementation that support timeout, but now we need to find a way to make our code thread safe.

We have to go back to our account class and do some changes.

public static object _locObject = new object();

public static void Transfer(double amount, Account fromAccount, Account toAccount)
{
    lock (_locObject)
    {
        fromAccount.Withdraw(amount);
        toAccount.Deposit(amount);
    }
}

We have to create a static lock object we can use to lock on. Because we are doing the lock in one signle operation our test will now run without any problem.

This is only a small overview of what CHESS can do.

Monday, May 11, 2009

How to test your multi-threaded code (part 2 of 3)?

Previously we saw how to build a test to find a multi-thread bug our your code. Now we will look at how to reproduce debug and fix it.

Remember our bank account class:

public class Account
{
   public double Balance { get; set; }

   private Account(double amount)
   {
       Balance = amount;
   }

   public static Account OpenNew(double amount)
   {
       return new Account(amount);
   }

   public void Deposit(double amount)
   {
       double tempAmount = Balance;
       // potential problem
       lock (this)
       {
           Balance = tempAmount + amount;
       }
   }

   public void Withdraw(double amount)
   {
       double tempAmount = Balance;
       // potential problem
       lock (this)
       {
           Balance = tempAmount - amount;
       }
   }
}

And our test:

[TestMethod()]
[HostType("Chess")]
public void BalanceMutiThreadTest()
{
   Account account = Account.OpenNew(10000);

   Thread thread = new Thread(a => ((Account) a).Withdraw(100));
   thread.Start(account);
   account.Deposit(100);
   thread.Join();

   Assert.AreEqual(10000, account.Balance);
}

Now if we look carefully at the test result detail, there is an explanation on how to reproduce this particular schedule. All you have to do is to copy/paste the code provided just before your test method call.

[TestMethod()]
[HostType("Chess")]
[TestProperty("ChessMode", "Repro")]
[TestProperty("ChessBreak", "BeforePreemption")]
#region ChessScheduleString (not human readable)
[TestProperty("ChessScheduleString", @"bpilaiaaaaaaaaaaaeaaonlnahgabmejjgcfcgcpgnmkhlhpekpfeknhoahekbaiiagabdcenijaeabaommbiimnogjcombngjehcdcjklckibmkgffggffnggbgeammonjnlmphnohloplnphnohloplnphlkdljneochphnpppdpfmgggeabgmpgmoeknkmjjocbiakkmibpdphohmbpdpcchomnfpodnhpidfpappfpfhhpponplpkgpmdelpppbgpkplkpoflfmbopdpkgdppbppfpephpocllfpedhppkopjkppjlohpppohpaaldcaoojfhfaaaaaa")]
#endregion
public void BalanceMutiThreadTest()
{
   Account account = Account.OpenNew(10000);

   Thread thread = new Thread(a => ((Account) a).Withdraw(100));
   thread.Start(account);
   account.Deposit(100);
   thread.Join();

   Assert.AreEqual(10000, account.Balance);
}

(your code may be different)

With that code in place if you run your test again (without the debugger) you will see that only one schedule was evaluated and you got the same result as the previous test. From there, as a tester, you job is done. You check in the code and hand it to the development team. If you are a member of a small team, as I usually am, you may be the tester and the developer so you’ll have to debug the code yourself.

Now run this test again but this time with the debugger. The execution should stop just before one of the lock statement. If you step once you will be able to inspect tempAmount and Balance values and see the problem. Between the line where the debugger stop and the previous line another thread changed the Balance value. Now you can see the don’t match.

Of course in this case the solution is easy, we just have to put the tempAmount assignation inside of the lock block but in the next post you will see a case where the solution is not so obvious.

Tuesday, May 5, 2009

How to test your multi-threaded code (part 1 of 3)?

CHESS is the answer. At least this is what we have best right now.

In multi-threaded application, bug are hard to almost impossible to find. For the last years the only true way to detect threading problems was to run load test until the system crash. Once it does, every once in thousands of iterations, the tools to reproduce and debug the problem were inexistent.

The RiSE (Research in Software Engineering) team at Microsoft have been working for a long time on a product called CHESS. When run with CHESS, you unit tests will try every possible combination of thread interleave to find a case where you application crash or worst doesn’t give you the result you expect.

Here is a simple demo to show you the power of CHESS. Let’s start with a banking account management system.

public class Account
{
    public double Balance { get; set; }

    private Account(double amount)
    {
        Balance = amount;
    }

    public static Account OpenNew(double amount)
    {
        return new Account(amount);
    }

    public void Deposit(double amount)
    {
        double tempAmount = Balance;
        // potential problem
        lock (this)
        {
            Balance = tempAmount + amount;
        }
    }

    public void Withdraw(double amount)
    {
        double tempAmount = Balance;
        // potential problem
        lock(this)
        {
            Balance = tempAmount - amount;
        }
    }
}

Of course I voluntarily introduce “potential problems” to show how CHESS will get them. With that class you can write this test:

[TestMethod()]
public void BalanceTest()
{
    Account account = Account.OpenNew(10000);

    account.Withdraw(100);
    account.Deposit(100);

    Assert.AreEqual(10000, account.Balance);
}

This will always run fine as it is single threaded. Now what if we change it a little to make it multi-threaded:

[TestMethod()]
public void BalanceMutiThreadTest()
{
    Account account = Account.OpenNew(10000);

    Thread thread = new Thread(a => ((Account) a).Withdraw(100));
    thread.Start(account);
    account.Deposit(100);
    thread.Join();

    Assert.AreEqual(10000, account.Balance);
}

As you can see here we put the withdraw part in a new thread. But even then we can run this test again and again without any problem. You can put it in a loop if you want and never being able to make it return an invalid balance.

Once you have CHESS installed on your system the only thing you have to do is to add a HostType attribute to your method.

[TestMethod()]
[HostType("Chess")]
public void BalanceMutiThreadTest()
{
    Account account = Account.OpenNew(10000);

    Thread thread = new Thread(a => ((Account) a).Withdraw(100));
    thread.Start(account);
    account.Deposit(100);
    thread.Join();

    Assert.AreEqual(10000, account.Balance);
}

Now when you run this test you should get something like:

Assert.AreEqual failed. Expected:<10000>. Actual:<10100>.

You should also have noticed that it took a little longer to run the test. This is because the CHESS host scans your code to build an execution schedule for every possible thread interleave that CHESS can detect. If you double click on the test result you will see how many schedules that were tried before finding the bug, in my case it is 3.

Next time we will see how to reproduce and debug that code.