CODE: Sequoia

Saturday, December 02, 2006

Auto reset event debugging technique

Common error of auto reset event

In Win32 API, you can use an "event object" to synchronize multiple threads. An event has one of two state: signaled or not-signaled. When it's not-signaled, the waiting thread is blocked on WaitForSingleObject call, and it's unblocked when the event is signaled. You can signal a event by SetEvent() API function. Thread synchronization with event objects is known to be error prone. One typical error is "slipped event", or SetEvent() is called on already signaled event and does not have any effect. Let' say, you write a one-length FIFO, where one thread push a value and the other thread pulls it.
// variable to pass value from push thread
// to pull thread.
int plate;

// event is created with auto-reset, initial 
// value is not signaled.
HANDLE hasItem = CreateEvent(NULL, FALSE, FALSE, NULL);

void push(int item){
  plate = item;
  SetEvent(hasItem);
}

int pull(){
  WaitForSingleObject(hasItem, INFINITE);
  return plate;
}
If push() is called twice before pull(), value in plate is overwritten and lost. Slipped event is very common, and hard to avoid. It's also difficult to debug because the effect may be visible long time later.

Slipped event debugging technique

There is a way to make your life easier: Use semaphoe instead of auto-reset event. If you read the MSDN carefully, you may find that auto-reset event is same as semaphoe with maximum count = 1. Therefore, you can safely replace your event with semaphoe. There is a big advantage of semaphoe over event. When you call ReleaseSemaphoe (SetEvent of semaphoe) on a signaled semaphoe (count = 1), it returns FALSE. Therefore, you can detect slipped event by checking the return value of ReleaseSemaphoe.
// variable to pass value from push thread 
// to pull thread.
int plate;

// semaphoe with initial value is 0, maximum
// value is 1. It's equivalent to auto-reset 
// event.
HANDLE hasItem = CreateSemaphoe(NULL, 0, 1, NULL);

void push(int item){
  plate = item;
  BOOL bResult = ReleaseSemaphoe(hasItem, 1, NULL);
  assert(bResult);
}

int pull(){
  WaitForSingleObject(hasItem, INFINITE);
  return plate;
}

Sunday, October 08, 2006

How to shutdown worker thread on Form closing?

Use BeginInvoke instead of Invoke.

Let's assume you are writing a .NET application which has a progress bar.

  • It starts a worker thread when the application starts.
  • The worker thread does some lengthy work.
  • The worker thread calls OnProgress() delegate whenever some progress happens.

Since you may not call any Control methods from non-UI thread, the implementation of OnProgress would be something like this (Use Control.Invoke):

private void OnProgress(int percent){
  Invoke(new MethodInvoker(delegate(){
    progressBar.Value = percent;
  }));
}

ObjectDisposedException!?

However, you have a problem here. OnProgress() is called from the worker thread which does not know anything about the UI thread. For example, it might be called *after* the Form is closed. If it happens, you get ObjectDisposedException.

How about stopping the worker thread in OnClosed()?

You might want to try stopping the worker thread in Form.OnClosed() so that OnProgress() cannot be called after Form's disposal.

protected override void OnClosed(EventArgs e) {
  // ...
  // cancel worker thread
  // ...
  workerThread.Join();
  base.OnClosed(e);
}

Opps, it's now dead locked.

Unfortunately, the solution is not right. OnClosed() is called from UI thread, and it is blocked at Thread.Join(). While it's blocked, OnProgress() is also blocked because Invoke() requires the UI thread to work. (Remember: The delegate passed to Invoke() is executed by the UI thread.)

So, what should I do?

Use BeginInvoke() instead of Invoke(). BeginInvoke() does not block the caller thread, so the deadlock can be avoided.

How about EndInvoke()?

You might wonder when to call EndInvoke(). If you call EndInvoke(), the caller thread is blocked until the delegate is processed - it's essentially same as Invoke(). Therefore, you have the same deadlock issue again.

Fortunately, you don't have to call EndInvoke(). It's not well documented in MSDN, but it is "officially" true. See the comments of the blog entry below: http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx

Monday, February 20, 2006

My first Web Service experience

I'm a software engineer, and deal with C++ everyday. While it is fun, I have to admit I'm somewhat far from up-to-date topics such as "Web Service". In this president day weekend, I had a chance to jump into it. And, it was fantastic experience to know what is "Web Service". In short, "Web Service" enables me to access services of the Web site programatically. The first thing I did was going to Google and got Google API. http://www.google.com/apis/ I think what the API does explains what is "Web Service" very well. It allows me to use Google Search engine through my program. The API comes with WSDL file. Actually, I don't know what is it exactly yet, but it seems to describe:
  • What kinds of methods does Google exposes to us?
  • How to use these methods? What Parameters, What return type, etc.
For my first Web Service experience, I picked a method called "doSpellingSuggestion". It uses Google's spelling suggestion functionality. The WSDL file is language independent, and we can get C# version of "WSDL" out of it. The C# version of WSDL lets us to use the Google API through C# language. The conversion is done with wsdl.exe which comes with .NET framework SDK. % wsdl GoogleSearch.wsdl Then I got GoogleSearchService.cs . Next step is to write C# application program to use the API. BTW, the xxx... below is my Google license code.
using System;

public class GoogleSpell {
 static public void Main(){
   GoogleSearchService service = new GoogleSearchService();
   string result = service.doSpellingSuggestion("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "atmosphire");
   Console.WriteLine(result);
 }
}
Then compile the code with GoogleSearchService.cs, and run. Google checks the wrong spelling "atmosphire" and correct it to "atmosphere". Wow. It is that easy!

Sunday, February 19, 2006


Moto's picture Posted by Picasa