Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Wednesday, October 01, 2008

Does Multi-Threaded Winforms application really exist?

For my thesis, I wanted a powerful MDI application. By powerful, I mean which can process at least 100 child forms at a time. Each form does a bunch of background work and for this reason I wanted a truly multithreaded windows application. So I went ahead and spawned the child forms using ThreadPool.

The child form is pretty simple for this example, it does not do any major background work. It just has a browser control and when clicked on a menu item, it sleeps for 10 seconds and sets the text of the form to "Done". I have two menu options, one to do work in the background and one which does not do that work in the background. But when you launch a Multithreaded MDI, you expect the work to be done in the background, irrespective of the way you code it.

private void someWorkNotInBackgroundToolStripMenuItem_Click(object sender, EventArgs e)
{
Thread.Sleep(10000);
this.Text = "Done";
}
A true multithreaded application should not stuck up other child windows when it does the above shown work.


But that is not the case. So you have do something like shown below, for the application to be truly responsive irrespective of the background work it does.



private void someWorkInBackgroundToolStripMenuItem_Click(object sender, EventArgs e)
{
new MethodInvoker(() => Thread.Sleep(10000)).BeginInvoke(new AsyncCallback(it => this.Text = "Done"), null);
}

A delegate is used to asynchronously perform background jobs inside a windows form. Doing so does not stuck up the application unlike the first case.


Using ThreadPool to spawn threads



Well, if you want a truly multithreaded application, then you have do all tasks in background using BeginInvoke() as shown the previous code snippet. Spawning child threads to create MDI Children would not help. But anyway, in this section, I show you how to use ThreadPool and just because we are talking about Multithreaded Windows, I show the windows in the worker thread.



Firstly, in order to use thread pool, we need a worker item. For this worker item, it is recommended you create a class that represents this worker item. My worker item is shown below.



class ThreadPoolWorkerItem
{
/// <summary>
///
The tracker supposedly keeps track of the worker item status.
///
Though in this example, it does not work. Usually in the work method,
///
you do a Set() on this tracker which signals the WaitHandle.
/// </summary>
private ManualResetEvent tracker;

/// <summary>
///
Initializes a new instance of the <see cref="ThreadPoolWorkerItem"/>
class.
/// </summary>
/// <param name="tracker">
The tracker.</param>
14:
public ThreadPoolWorkerItem(ManualResetEvent tracker)
{
this.tracker = tracker;
}

/// <summary>
///
Performs the work done by the current ThreadPool Worker Item.
/// </summary>
/// <param name="threadState">
State of the thread.
</param>
public void work(object threadState)
{
ChildForm cf = threadState as ChildForm;
//cf.Show() is invalid. It throws an InvalidOperationException, since cf was not created in this thread.
cf.Invoke(new MethodInvoker(() => cf.Show()));
cf.FormClosed += new FormClosedEventHandler(cf_FormClosed);
//The two statements below simulate a job that takes 1 second to work and then it notifies using the tracker.
//That is the way usually ThreadPool worker items should work.
//Thread.Sleep(1000);
//tracker.Set();
}

/// <summary>
///
Handles the FormClosed event of the cf control.
///
In this event, we supposedly inform the waiting thread about the current worker item's job done.
///
It does not work in this example.
/// </summary>
/// <param name="sender">
The source of the event.
</param>
/// <param name="e">
The <see cref="System.Windows.Forms.FormClosedEventArgs"/> instance containing the event data.
</param>
void cf_FormClosed(object sender, FormClosedEventArgs e)
{
tracker.Set();
}
}

The code explains how threadpool worker items should be created.


The code for adding worker items to the ThreadPool is shown below.





   1: /// <summary>


   2: /// Does the work.It creates ThreadPoolWorkerItems and adds it to the ThreadPool.


   3: /// </summary>


   4: private void DoWork()


   5: {


   6:     ThreadPool.SetMaxThreads(2, 2);


   7:     ManualResetEvent[] trackers = new ManualResetEvent[Maxthreads];


   8:     for (int i = 0; i < Maxthreads; i++)


   9:     {


  10:         trackers[i] = new ManualResetEvent(true);


  11:         ThreadPoolWorkerItem item = new ThreadPoolWorkerItem(trackers[i]);


  12:         this.Invoke(new MethodInvoker(() =>{                                                  {


  13:                      ThreadPool.QueueUserWorkItem(item.work, new ChildForm("http://google.com") { MdiParent = this });


  14:                 }));


  15:     }


  16:     WaitAll(trackers);


  17: }




The code explains how you actually create and add worker items to  thread pool. In this case using a "ThreadPool.QueueUserWorkItem(item.work,new ChildForm("http://google.com"){MdiParent = this});" would give a ThreadStateException (for other cases, you might see a InvalidOperationException). For that reason, a this.Invoke() is used to create the child form and spawn it.



So you schedule some jobs in the ThreadPool and you should wait for them to complete. So how do you wait? We use WaitHandle.WaitAll(trackers); which suspends the current thread until all the spawned worker items in the ThreadPool are completed, whose manual reset events are the "trackers".



But in our case, it does not work. So I thought, it has some issues and researched online. I found an alternative WaitAll() to be used in Windows Forms.





   1: /// <summary>


   2: /// Waits on all the wait handles to complete execution.


   3: /// The WaitHandle in this case is a manual reset event.


   4: /// </summary>


   5: /// <param name="waitHandles">The wait handles.</param>


   6: private void WaitAll(ManualResetEvent[] waitHandles)


   7: {


   8:     foreach (WaitHandle myWaitHandle in waitHandles)


   9:         WaitHandle.WaitAny(new WaitHandle[] { myWaitHandle });


  10: }




The WaitAll() to be used in Windows Forms. Note that none of the concepts explained would really create a multi-threaded windows forms applications where each child form run in its own thread. But the information I obtained is shared here.



Using Threads without ThreadPool



Threads could directly be created and spawned which shows the Child Forms. Something like that could be done as shown.





   1: for (int i = 0; i < Maxthreads; i++)


   2: {


   3:         new Thread(() =>{


   4:            this.Invoke(new MethodInvoker(() => 


   5:                 new ChildForm("http://google.com") { MdiParent = this }.Show()));


   6:                          }).Start();


   7: }




We create a thread which again delegates its job of creating a child window the the parent form. So is this going to be helpful? So can you create a truly multithreaded MDI application?



Again, I repeat, from what I know and from what I researched, you cannot create Child forms in an MDI application where each Child runs in its own thread. The form UI thread has to be spawned from the parent MDI form itself, thereby making it impossible for the thread to survive. As soon as the Show() is done, the thread dies, because it has nothing else to do!



Using Application.Run() to create child MDI forms



First of all, this is something I found out just now. So it has to be lame and you should probably not use this at any cost. But anyway here the code is.





   1: /// <summary>


   2: /// Handles the Click event of the launchUsingApplicationRunToolStripMenuItem control.


   3: /// It launches the Child windows using Application.Run().


   4: /// For it work, you should set the AparmentState of the thread to STA. Right now, I use a depricated way


   5: /// to do that. Optionally you can add a method with attribute set to STAThread, like in the Program.cs Main()


   6: /// </summary>


   7: /// <param name="sender">The source of the event.</param>


   8: /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>


   9: private void launchUsingApplicationRunToolStripMenuItem_Click(object sender, EventArgs e)


  10: {


  11:     for (int i = 0; i < 10; i++)


  12:     {


  13:         new Thread(() =>


  14:                        {


  15:                            ChildForm cf = new ChildForm("http://google.com") { };


  16:                            this.Invoke(new MethodInvoker(() => cf.MdiParent = this));


  17:                            Application.Run(cf);


  18:                        }) { ApartmentState = ApartmentState.STA }.Start();


  19:     }


  20: }




Do no use this. It just shows how retard I am.



Finally, how to make Multithreaded MDI?



From what I know, you cannot make a child form run in its own thread. But you can make the work it performs using asynchronous calls or threads.



So for every heavy job your child form does, you have spawn a thread or use asynchronous calls, iff you want your application to be responsive.



Disclaimer: I am no guru either in WinForms or Multi-threading. But I tried to share what I learnt writing applications for my thesis and job.

Sunday, February 03, 2008

Matching two arrays - One Line Beauty ..

Recently I wrote some "useful" code which I would probably release online as an open source; if things do not go as expected. Anyway during that, I had a requirement where I have to match two arrays and return the match %. So let us do it in C# 2.0 or Java for that matter. Look at my code ...

public double match(string[] array1, string[] array2)
{
int common = 0;
foreach(string val1 in array1)
foreach(string val2 in array2)
if(val1.equals(val2)) common++;
double avg = (array1.Length + array2.Length)/2;
return common/avg;
}


Now let us do it in C# 3.0 Way, using extension methods which are already written for us ..

public double match(string[] array1,string[] array2)
{
int common = array1.Where(item=>array2.Contains(item)).Count;
double avg = (array1.Length+array2.Length)/2;
return common/avg;
}


Isn't that sweet? Well, it definitely is sweet. You could do something like that even in Groovy..

public match(array1,array2)
{
def common = array1.find(it->array2.contains(it)).size();
def avg = (array1.length()+array2.length())/2;
return common/avg;
}


Well, the functions size() might either be length() or count() which I usually am confused and since I always an IDE to code, I usually do not take the pain to remember these simple(but important) details. Anyway, if you want to pick the common elements in 10 arrays, even then the code in C# 3.0 or Groovy is going to be 3-4 lines. So it 400% less code?

The point here is that languages are getting sexier with time and it is really fun to write amazingly compact code. For those who haven't tried LINQ, should really take a look at it. By the way, I did a little LINQ to XML and with very little code, it makes using RESTful web services very easy. Hats off! to all the genius who came up with these ideas (of course, Microsoft did not invent closures...)

Wednesday, January 30, 2008

String comparisons : == vs. equals()

It is a well known that you cannot compare two objects obj1 and obj2 using == operator. == operator checks for the equality of the references not the equality of the objects. Just a little snippet is shown below

Point p1 = new Point(100,100);
Point p2
= new Point(100,100);
System.out.println(p1
==p2); // ??
The above code snippet, when run, displays "false" in the output console. But still both p1 and p2 refers to a coordinate (100,100). So if you wish to get your equality to be true for such cases (where the object content! matches), then you should be using "equals()" method. This works for almost all the classes shipped with JDK. For this to work on the objects of the classes that you write (eg: Employee class or Chair or Bench.java), then you should override the method "public boolean equals(Object two)" and implement your meaning of equality of the objects of your class. Also note that, it is highly recommended and important that you override the "int hashCode()" method when you override the "equals" method.

Anyway, now when we deal with String comparisons, one should remember that "Strings" are not value types but are reference types (I mean String is a class). So Strings have to compared for equality using equals method instead of == operator. But the way the JVM is implemented, there are cases under which the == returns true for matching strings. So what are the cases?

Case 1: Where == returns true

String s1 = "Krishna";
String s2 = "Krishna";
if(s1==s2)
System.out.println("Strings are equal!!");
else
System.out.println("You cannot use == here");

Trying running the code as it is and you see the "Strings are equal" on the console. Well can you guess why?

The reason for the == operator to work in this case is that the Java compiler optimizes the strings s1 and s2. Since they are both "initialized" to "Krishna", instead of having two different string objects, optimization is done by having only one object and both s1 and s2 refer to the same "Krishna" object. Remember that the == operator only works for "static" kind of initialization. So if it was the case where s1 = new String("Krishna"); then s1 == s2 would return false instead of true, though it appears both are being initialized to the same "Krishna". Let us see another case where s1 == s2 fails.

Case 2: Where == returns false and equals() return true

String s1 = "Krishna";
String s2 = new String(s1);
if(!(s1==s2))
System.out.println("You cannot use == here");
else if(s1.equals(s2))
System.out.println("You should use 'equals' method in all cases");
Anyway the moral of the story is that you should always use "equals" to compare strings and should never use == even though it works in few cases.

Tuesday, January 08, 2008

Configuring SWT Browser Preferences (2)

In one of my previous posts, I blogged about the way one could set SWT Browser Widget Preferences and there has been a comment on my blog!!! (well apart from the comments that my friend Suri makes)
The comment has rightly pointed out to a way that one could programatically set the preferences of SWT Browser widget. The way it could be done is shown in the following code snippet.

Browser browser = MozBrowserUtil.openMozillaBrowser("about:blank");
nsIServiceManager servMgr = Mozilla.getInstance().getServiceManager();
nsIPrefBranch prefs = ( nsIPrefBranch )servMgr.
getServiceByContractID("@mozilla.org/preferences-service;1",
nsIPrefBranch.NS_IPREFBRANCH_IID);

prefs.setIntPref("network.proxy.type", 1);
prefs.setCharPref("network.proxy.http", host);
prefs.setIntPref("network.proxy.http_port", port);

browser.setUrl(url);


Again, I thank the anonymous commentor for bringing this to my notice. I appreciate all your comments and would be better if you leave me atleast an email or a URL to your page/blog so that I can get back to you.