thread synchronization and GUI problem

G

Guest

Hello, I am using Visual Studio 2005 .Net, coding in C#. I am working
through the threading walkthrough:

ms-help://MS.VSCC.v80/MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_fxmclicc/html/7bc03b7b-d680-499b-8179-5f414b2d650c.htm

and have been able to get that to work as designed. However, I coded up a
slight variant of that example to update the GUI while each thread is running
rather than only at the end of each thread. My experience is that the GUI is
locked up while each thread is running, though. I have a simple Windows App
form with 2 buttons, 2 text boxes, and 2 labels, and then a class called
Loopy (analogous to the walkthrough Calculator class) [attached below]. My
intention is to loop from 1 to N, where N in a number entered in a text box,
and then display the value of the loop variable on the GUI by updating a
label. Each button-textbox-label combo performs a different loop in a
separate thread. Is there a glaring error in the code or do I just have a
conceptual misunderstanding?

Thanks,
Don


namespace ThreadEventTest
{
public partial class Form1 : Form
{
Loopy Loopy1;
public delegate void LoopWHandler(int current);
public delegate void LoopCHandler();

public Form1()
{
InitializeComponent();
Loopy1 = new Loopy();
Loopy1.Loop1Working += new
Loopy.Loop1WorkingHandler(this.Loop1WHandler);
Loopy1.Loop2Working += new
Loopy.Loop2WorkingHandler(this.Loop2WHandler);
Loopy1.Loop1Complete += new
Loopy.Loop1CompleteHandler(this.Loop1CHandler);
Loopy1.Loop2Complete += new
Loopy.Loop2CompleteHandler(this.Loop2CHandler);
}

private void button1_Click(object sender, EventArgs e)
{
Loopy1.var1 = int.Parse(textBox1.Text);
// Disables the btnFactorial1 until this calculation is complete.
button1.Enabled = false;
Loopy1.ChooseThreads(1);
}

private void button2_Click(object sender, EventArgs e)
{
Loopy1.var2 = int.Parse(textBox2.Text);
// Disables the btnFactorial1 until this calculation is complete.
button2.Enabled = false;
Loopy1.ChooseThreads(2);
}

protected void Loop1WHandler(int current)
// Displays the returned value in the appropriate label.
{
this.BeginInvoke(new LoopWHandler(L1WHandler), new Object[] {
current });
}

protected void Loop2WHandler(int current)
{
this.BeginInvoke(new LoopWHandler(L2WHandler), new Object[] {
current });
}

protected void Loop1CHandler()
// Displays the returned value in the appropriate label.
{
this.BeginInvoke(new LoopCHandler(L1CHandler), new Object[] {});
}

protected void Loop2CHandler()
{
this.BeginInvoke(new LoopCHandler(L2CHandler), new Object[] {});
}

public void L1WHandler(int current)
{
label1.Text = current.ToString();
}
public void L2WHandler(int current)
{
label2.Text = current.ToString();
}
public void L1CHandler()
{
button1.Enabled = true;
}
public void L2CHandler()
{
button2.Enabled = true;
}
}
}

namespace ThreadEventTest
{
public partial class Loopy : Component
{
public int var1;
public int current1;
public int var2;
public int current2;

public delegate void Loop1WorkingHandler(int current);
public delegate void Loop2WorkingHandler(int current);
public delegate void Loop1CompleteHandler();
public delegate void Loop2CompleteHandler();

public event Loop1WorkingHandler Loop1Working;
public event Loop2WorkingHandler Loop2Working;
public event Loop1CompleteHandler Loop1Complete;
public event Loop2CompleteHandler Loop2Complete;

public System.Threading.Thread Loop1Thread;
public System.Threading.Thread Loop2Thread;

public void Loop1()
{
for (int i = 1; i <= var1; i++)
{
lock (this)
{
current1 = i;
}
Loop1Working(current1);
}
Loop1Complete();
}

public void Loop2()
{
for (int i = 1; i <= var2; i++)
{
lock (this)
{
current2 = i;
}
Loop2Working(current2);
}
Loop2Complete();
}

public void ChooseThreads(int threadNumber)
{
// Determines which thread to start based on the value it
receives.
switch (threadNumber)
{
case 1:
// Sets the thread using the AddressOf the subroutine
where
// the thread will start.
Loop1Thread = new System.Threading.Thread(new
System.Threading.ThreadStart(this.Loop1));
// Starts the thread.
Loop1Thread.Start();
break;
case 2:
Loop2Thread = new
System.Threading.Thread(new
System.Threading.ThreadStart(this.Loop2));
Loop2Thread.Start();
break;
}
}

public Loopy()
{
InitializeComponent();
}

public Loopy(IContainer container)
{
container.Add(this);

InitializeComponent();
}
}
}
 
J

Jon Skeet [C# MVP]

Don Tucker said:
Hello, I am using Visual Studio 2005 .Net, coding in C#. I am working
through the threading walkthrough:

ms-help://MS.VSCC.v80/MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.VisualStudio.v
80.en/dv_fxmclicc/html/7bc03b7b-d680-499b-8179-5f414b2d650c.htm

and have been able to get that to work as designed. However, I coded up a
slight variant of that example to update the GUI while each thread is running
rather than only at the end of each thread. My experience is that the GUI is
locked up while each thread is running, though. I have a simple Windows App
form with 2 buttons, 2 text boxes, and 2 labels, and then a class called
Loopy (analogous to the walkthrough Calculator class) [attached below]. My
intention is to loop from 1 to N, where N in a number entered in a text box,
and then display the value of the loop variable on the GUI by updating a
label. Each button-textbox-label combo performs a different loop in a
separate thread. Is there a glaring error in the code or do I just have a
conceptual misunderstanding?

I haven't got time to test it right now (I'm just about to leave) but I
suspect the problem is that you're doing a tight loop in your other
threads, so you don't give the UI thread a chance to get in. Put a call
to Thread.Sleep in while you're counting. That way you're much more
likely to be able to actually *see* the counting rather than it being a
blur, too :)
 
W

Willy Denoyette [MVP]

Don Tucker said:
Hello, I am using Visual Studio 2005 .Net, coding in C#. I am working
through the threading walkthrough:

ms-help://MS.VSCC.v80/MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_fxmclicc/html/7bc03b7b-d680-499b-8179-5f414b2d650c.htm

and have been able to get that to work as designed. However, I coded up a
slight variant of that example to update the GUI while each thread is
running
rather than only at the end of each thread. My experience is that the GUI
is
locked up while each thread is running, though. I have a simple Windows
App
form with 2 buttons, 2 text boxes, and 2 labels, and then a class called
Loopy (analogous to the walkthrough Calculator class) [attached below].
My
intention is to loop from 1 to N, where N in a number entered in a text
box,
and then display the value of the loop variable on the GUI by updating a
label. Each button-textbox-label combo performs a different loop in a
separate thread. Is there a glaring error in the code or do I just have a
conceptual misunderstanding?

You shouldn't update the UI at that rate, first it makes no sense because
windows cannot paint at that rate, second you are flooding the UI thread
message queue with thousands of messages, the result is that the mouse and
KB becomes non-responsive.
If you click a mouse button or hit a key, the mouse message is simply
queued up behind the possibly thousands or more messages already in the
queue. This gives the illusion of a crashed app, because it's
non-responsive.
What you have to do is find a point in time when it's appropriate to update
the UI, for instance only after x iterations. Where x iterations do take
100-200msec. for instance, that way you only update a pace of 5 - 10 times a
second. Note that you might give up your thread quantum when doing the
update by calling Thread.Sleep(0), this to make sure the UI thread gets a
chance to run when running a tight loop on a worker thread.

Some other remark is that you should avoid using "this" as a lock
(lock(this), in reality the lock isn't even needed as the variable you are
incrementing is not shared.

Willy.

Willy.
 

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