Click to See Complete Forum and Search --> : Timer and function calls -- do i need multithreading?


xCoder
February 4th, 2008, 02:52 PM
Hello All,

Using: C# - Visual Studio 2005 (.Net FW 2.0)

I am working on an application that has a function call which will retrieve a list of online computers in local network. That is not the problem it's self.
The function call for this task will get the list and return it in an arraylist object.

When i press the retrieve button, a timer will be enabled that will provide visual feedback to use about progress, since no progress can be calculated here the progress bar goes from 0 to 100 then back to 0 again and so on.


//Retrieve button click
private void toolbtnNew_Click(object sender, EventArgs e)
{


lblStatus.Text = "Listing LAN computers...";
tmrLoading.Enabled = true;


ArrayList list = NetworkBrowser.getListOfComputers();


for (int i = 0; i < list.Count; i++)
lstExplore.Items.Add(list[i]); //LstExplore is a lstView
tmrLoading.Enabled = false;
lblStatus.Text = "Done!";
LoadingProgress.Value = 0;

}
//Timer code
private void tmrLoading_Tick(object sender, EventArgs e)
{
if (LoadingProgress.Value == 100) LoadingProgress.Value = 0;
LoadingProgress.Value+=5;
}


PROBLEM: When Retrieve button is pressed, no visual feedback is given as no update to the progress bar value seem to happen, i am guessing that it's because the getListOfComputers() is a blocking function call, it will stop anything from executing until it's done. But what about timers, aren't they multithreaded?

What would you recommend me to do to solve this tiny problem? I want to know this because it's little things that makes you learn more. So i would like to know what to do when coming to such situation in this project and any other projects.
You are also welcome to give me hints and leave the rest to me.

Best regards and thanks in advance,
xCoder

TheCPUWizard
February 4th, 2008, 02:54 PM
Windows Forms Timers simply post a message in the message queue, and are not (from a programmers perspective) multi-threaded.

The proper thing to do is to move your processing to a background thread. The simplest way to do this is to "QueueUserWorkItem", then you do not have to do any management on the thread, the C# runtime will take care of it alll.

xCoder
February 4th, 2008, 03:26 PM
Thanks TheCPUWizard. I have successfully used the QueueUserWorkItem passing on object of WaitCallback with address of the function or method i want to call.

ThreadPool.QueueUserWorkItem(new WaitCallback(NetworkBrowser.getListOfComputers));
ArrayList list = NetworkBrowser.result;
for (int i = 0; i < list.Count; i++)
lstDownloads.Items.Add(list[i].ToString());

Knowing that the thread pool will only call my function when it is available, the loop after the function call should not be there because it will read the null version of NetworkBrowser.result array list which is null because the getListOfComputers() was not called and thus the list was not initialized. Since the function is in an another class, how can the Windows Form class in my application going to know that the getListOfComputers has been called to read result from NetworkBrowser class?

Again, i thank you for such a quick reply.

--------------------
EDIT
I have edited the NetworkBrowser.getListOfComputers take the instance of my form (this) as a parameter and it will call the ReadResult which will read the result arraylist from the NetworkBrowser class:

public static void getListOfComputers(object caller)
{
....... code here ....
((frmMain)caller).ReadResult();
}

//frmMain.ReadResult:
public void ReadResult()
{
frmMain.CheckForIllegalCrossThreadCalls = false;
ArrayList list = NetworkBrowser.result;
for (int i = 0; i < list.Count; i++)
lstExplore.Items.Add((string)list[i]);
tmrLoading.Enabled = false;
lblStatus.Text = "Done!";
LoadingProgress.Value = 0;
}

Is this approach considered good OOP?

TheCPUWizard
February 4th, 2008, 03:46 PM
The easiest way is to actually use the "Invoke" method on a control from your "WorkItem". This is the way a background thread can (indirectly) access the control.

An alternative would be to use a Synchronization object (Monitor, Semaphore, Mutex).

Finally (for this fairly trivial task) you could use a simple boolean that you check within the timer procedure.