Newbie User Interface hangs in multi-thread app

G

Guest

Hi,
* Apologies for reposting this from .NET Academic *
I am having problems updatingh the user interface in a multi-threaded
application.

BACKGROUND
My App has a user interface (the starting class containing main) and a
CPU class to handle many asynchronous comms routines.
The user interface will be kept updated on the status of the comms by the
CPU class.

My user interface creates an instance of a class called CPU and passes itself
in the constructor this way the CPU can update the user interface by calling
a method of UI

PROBLEM
The user interface is becoming unresponsvie.
The cursor turns to the hour glass and it doesnt repaint
Although all the comms threads run happily in the background as soon as
the CPU tries to call the UpdateScreen method the UI hangs.

ASSISTANCE REQUIRED
Could you please advise me on how i should go about resolving such a problem.
I may well be using bad coding strtegy so pleas advise as you see fit on any
aspect.

Thanks,
Shaun

PSEUDO CODE
// within the UI class
private CPU theCPU;
public UI()
{
theCPU = new CPU(this);
}

UpdateScreen(string status)
{
textBox1.Text = status;
panel1.Visible= ! panel1.Visible;
}

// within the CPU class
public CPU (UI userInterface)
{
this.userInterface = userInterface;
// start threads to run async comms
}

private void ReceivedStatusChange()
{
userInterface.UpdateScreen("Some new status info");
}
 
M

Marc Gravell

Firstly - are you calling the method directly or via (the form).Invoke(...)?

Secondly - as a design principle, I wouldn't recommend letting the CPU class
know about the specific UI; I'd do this with events, i.e. have some events
on the CPU class (StatusChanged, ProgressChanged, etc) which the UI
subscribes to (for each instance of CPU), and then does something like

public class CPU {
public event ProgressChangedEventHandler ProgressChanged;
protected void OnProgressChanged(int progressPercentage) {
if (ProgressChanged != null)
ProgressChanged(this, new
ProgressChangedEventArgs(progressPercentage,null));
}
}
public partial class UserControl1 : UserControl {
public UserControl1() {
InitializeComponent();
}
public void InitCPU(CPU cpu) { // attach the event-handler
cpu.ProgressChanged += CPU_ProgressChanged;
}
void CPU_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (InvokeRequired) { // throw at the UI thread
Invoke(new ProgressChangedEventHandler(CPU_ProgressChanged),
sender, e);
} else { // on the UI thread: process event
int progress = e.ProgressPercentage;
// do something with this
}
}
}

Does that help?

Marc
 
G

Guest

Thanks,
I'll apply it .. i wasnt using the Invoke which was probably the largest
problem.
Shaun
 
M

Marc Gravell

Another point:

Invoke blocks until the form picks up the method (on it's message queue),
invokes it and returns. If you have many threads you could see some blocking
as your threads struggle to get UI runtime.

You might want to consider using BeginInvoke instead, as this doesn't block.
I must admit that I'm a little hazy as to whether you need to religiously
call .EndInvoke with such methods; IIRC the 1.1 documentation hinted that
this might cause a leak (or is that just delegates?), but it doesn't mention
it on MSDN2 - in fact, the example uses .BeginInvoke without .EndInvoke.

You might also want to mark the handler as
[System.Runtime.Remoting.Messaging.OneWay] to help the compiler know it can
skip some of the outbound stuff - again, not sure if this is necessary, but
I've seen examples of such usage on this forum.

Ref: http://msdn2.microsoft.com/en-us/library/a06c0dc2.aspx

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top