468,780 Members | 2,349 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,780 developers. It's quick & easy.

thread hangs .. why ? + example project

Hi,

I am having a thread hang problem in my c# code.

The example on the website: http://csharp.web1000.com/ is a
simplified version of my problem.

You will see in the form that a method TestThread increments a number in the
textbox on the form.
TestThread is called from a worker thread (2nd thread) using a TimerThread.
Every 2 seconds it will increment the number in te text box.

First start the project from the form (form1 class is the startup object).
The Form is displayed. Now push the button, this will create the
TimerThread.
You now see nicely that the number increments every 2 seconds.

Now start the application from the class (class1 is the startup object).
Now the TimerThread will be created in the Class1 object.
You will see that the number is never incremented.

When stepping through the code you will see that the TestThread method is
called.
The TestThread code in the form properly detects that this is run from a
second thread (line InvokeRequired) and continues to the line where Invoke
is called. I use Invole so that the increment function would run on the
forms thread. It is here where the application seems to hang. The number in
the textbox is never incremented.

Can anyone explain me why this is happening or how to solve this ?
i was wondering, might this have something to do with Apparementthreading ?
(this is used when you start the application from the form (=startup
object)).
Maybe when you start it from the class this is no longer the case ?
Maybe it's something completely different.
Thanks for shedding some light in the darkness.

Regards, Serge

http://csharp.web1000.com/
Nov 15 '05 #1
5 3732
Thanks 100
That helps me a lot. I already read about this message loop a couple of time
but now it's slowly all coming together.

Now just for the test I followed your suggestion and added the
Application.Run to my code so that the message loop would be started.
Specifically i added in my static Main method (from the class that is
defined as start object) the Application.Run line.
The problem I have here is that the code from Main method after the
Application.Run line is only executed when the form is closed again. And
that is not what I want.

I can not simply add this code in the form.
The reason for this is that this form is a simple status window.
It is shared by all my applications and contains no intelligent code. It
just displays the progress of the application.
The real work is done in the classes that are set as the start-up object.

So now I need a way to figure out how to start my application from my class
and still start this form's message loop using the application.run line.
Do you know a way ?
I can think of some solution using delegates but don't know if this is the
best practise.

Thanks in advance for your suggestions,

Regards,

Serge
"100" <10*@100.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...
Hi Serge,

Application will hang for sure. When you use the Main method in Class1 as a start point. There is no code starting the message loop (Application.Run).
At least Control.Invoke uses messages to switch the execution over the UI
thread. Further more if there is no message loop you cannot move, resize,
close or do anything with the form. Form is freezed on the screen. It won't even repaint itself.

What you might want to do is.
1. Remove
_frmStatus.Show();
_frmStatus.Refresh();
from the code. You don't need them.
2. Insted of
while(true)
{
Thread.Sleep(1000);
}

put the following:
System.Windows.Forms.Application.Run(_frmStatus);

That makes the code almost like the one you have in the form's class.

HTH
B\rgds
100

"Serge" <se**********@hotmail.com> wrote in message
news:3f***********************@reader3.news.skynet .be...
Hi,

I am having a thread hang problem in my c# code.

The example on the website: http://csharp.web1000.com/ is a
simplified version of my problem.

You will see in the form that a method TestThread increments a number in the
textbox on the form.
TestThread is called from a worker thread (2nd thread) using a

TimerThread.
Every 2 seconds it will increment the number in te text box.

First start the project from the form (form1 class is the startup object). The Form is displayed. Now push the button, this will create the
TimerThread.
You now see nicely that the number increments every 2 seconds.

Now start the application from the class (class1 is the startup object).
Now the TimerThread will be created in the Class1 object.
You will see that the number is never incremented.

When stepping through the code you will see that the TestThread method is called.
The TestThread code in the form properly detects that this is run from a
second thread (line InvokeRequired) and continues to the line where Invoke is called. I use Invole so that the increment function would run on the
forms thread. It is here where the application seems to hang. The number

in
the textbox is never incremented.

Can anyone explain me why this is happening or how to solve this ?
i was wondering, might this have something to do with

Apparementthreading ?
(this is used when you start the application from the form (=startup
object)).
Maybe when you start it from the class this is no longer the case ?
Maybe it's something completely different.
Thanks for shedding some light in the darkness.

Regards, Serge

http://csharp.web1000.com/


Nov 15 '05 #2
forgot to explain in more detailed my reaction to your possible solution:

you said that it's better to have application.run instead of the

while(true)
{
Thread.Sleep(1000);
}

This is possible but in that case i create the status form after I start the
worker thread.
thereby I get into a problem becuase my worker thread might raise a status
event to be displayed on the status form before that the status form is
actually created.

i would prefer to create the status form first and then launch my worker
thread.

Thanks in advance for your suggestions,

Regards,
Serge
"100" <10*@100.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...
Hi Serge,

Application will hang for sure. When you use the Main method in Class1 as a start point. There is no code starting the message loop (Application.Run).
At least Control.Invoke uses messages to switch the execution over the UI
thread. Further more if there is no message loop you cannot move, resize,
close or do anything with the form. Form is freezed on the screen. It won't even repaint itself.

What you might want to do is.
1. Remove
_frmStatus.Show();
_frmStatus.Refresh();
from the code. You don't need them.
2. Insted of
while(true)
{
Thread.Sleep(1000);
}

put the following:
System.Windows.Forms.Application.Run(_frmStatus);

That makes the code almost like the one you have in the form's class.

HTH
B\rgds
100

"Serge" <se**********@hotmail.com> wrote in message
news:3f***********************@reader3.news.skynet .be...
Hi,

I am having a thread hang problem in my c# code.

The example on the website: http://csharp.web1000.com/ is a
simplified version of my problem.

You will see in the form that a method TestThread increments a number in the
textbox on the form.
TestThread is called from a worker thread (2nd thread) using a

TimerThread.
Every 2 seconds it will increment the number in te text box.

First start the project from the form (form1 class is the startup object). The Form is displayed. Now push the button, this will create the
TimerThread.
You now see nicely that the number increments every 2 seconds.

Now start the application from the class (class1 is the startup object).
Now the TimerThread will be created in the Class1 object.
You will see that the number is never incremented.

When stepping through the code you will see that the TestThread method is called.
The TestThread code in the form properly detects that this is run from a
second thread (line InvokeRequired) and continues to the line where Invoke is called. I use Invole so that the increment function would run on the
forms thread. It is here where the application seems to hang. The number

in
the textbox is never incremented.

Can anyone explain me why this is happening or how to solve this ?
i was wondering, might this have something to do with

Apparementthreading ?
(this is used when you start the application from the form (=startup
object)).
Maybe when you start it from the class this is no longer the case ?
Maybe it's something completely different.
Thanks for shedding some light in the darkness.

Regards, Serge

http://csharp.web1000.com/


Nov 15 '05 #3
100
Hi Serge,
Yes, you are right. The code after Application Run will be executed only
after the main window (passed to Run method) as a parameter is closed. In
this case when the application is closed. You cannot have alive windwos in
Windwos without messeage loop to dispatch messages to it. What I want to say
is all GUI applications has to have at least one UI thread (for windows
forms this is thread that eventually calls Application.Run) All UI
commponents has to be created by an UI thread.
What you might want to do in your case is to have 2 threads: one worker
thread and one UI thread to dispalay the status. See my code below.
The changes are:
1. I removed the Main method from Form1 class. We don't need it anymore.
2. I Added two new methods in Form1 class: Run and CloseForm(It could be
just Close, but I had to hide the base one).
3. Modified Class1's Main method.
4. I use the old timer to update the status form, but you can use whatever
fits better with your needs. The only things is that the changes you make to
any UI components has to be made by the UI thread owning the component.
Which means that all threads but the UI thread itself has to use
Control.Invoke method.
//-------------------- Form1.cs -------------------------------//
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace _ThreadTest
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
public System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox txtForm;
private System.Windows.Forms.Label label1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.txtForm = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// txtForm
//
this.txtForm.Enabled = false;
this.txtForm.Location = new System.Drawing.Point(8, 8);
this.txtForm.Name = "txtForm";
this.txtForm.Size = new System.Drawing.Size(48, 20);
this.txtForm.TabIndex = 0;
this.txtForm.Text = "0";
this.txtForm.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
//
// button1
//
this.button1.Location = new System.Drawing.Point(128, 8);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(192, 24);
this.button1.TabIndex = 1;
this.button1.Text = "Start Thread In Form Code - OK";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// label1
//
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif",
7.764706F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point,
((System.Byte)(0)));
this.label1.Location = new System.Drawing.Point(128, 8);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(184, 24);
this.label1.TabIndex = 2;
this.label1.Text = "Thread started from code = BAD";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(336, 36);
this.Controls.Add(this.button1);
this.Controls.Add(this.txtForm);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.Text = "Increment every 2 ses - thread test";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
public void Run()
{
Thread uiThread = new Thread(new ThreadStart(StatusThreadProc));
uiThread.ApartmentState = ApartmentState.STA;
uiThread.Start();
}
public void CloseForm()
{
if(InvokeRequired)
{
this.Invoke(new MethodInvoker(CloseForm));
}
this.Close();
}
/// <summary>Starts message loop (this thread is UI thread.)</summary>
public void StatusThreadProc()
{
Application.Run(this);
}

private void button1_Click(object sender, System.EventArgs e)
{
// Create the delegate that invokes methods for the timer.
TimerCallback timerDelegate = new TimerCallback(TestThread);

// Create a timer that waits one second, then invokes every second.
System.Threading.Timer timer = new System.Threading.Timer( timerDelegate,
"nothing" ,1000, 2000);

}

public void TestThread(object state)
{
if (! this.InvokeRequired )
{
base.Refresh();
txtForm.Text = (int.Parse(txtForm.Text) + 1).ToString();
}
else
{
Invoke(new WaitCallback(TestThread), new object[] {state});
}
}
}
}
//-------------------------------
Class1.cs ----------------------------------------
using System;
using System.Threading;
namespace _ThreadTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class Class1
{
private static Form1 _frmStatus;
private static TimerCallback timerDelegate;
private static System.Threading.Timer timer;
public Class1()
{
}

[STAThread]
static void Main(string[] args)
{

_frmStatus = new Form1();
_frmStatus.button1.Visible = false;
_frmStatus.Run();

// Create the delegate that invokes methods for the timer.
timerDelegate = new TimerCallback(_frmStatus.TestThread);

// Create a timer that waits one second, then invokes every second.
timer = new System.Threading.Timer( timerDelegate, "nothing" ,1000,
10000);
for(int i = 0; i < 20; i++)
{
//Do some job
Thread.Sleep(1000);
}
//Stop the close the status form. (This will exit the UI thread).
_frmStatus.CloseForm();

//You can do more work here

}
}
}
HTH
B\rgds
100
Nov 15 '05 #4
Possible the simplest way would be to create another form - MainForm -
which you will start with Application.Run
Form could be invisible - just hide it on load for example. Show your status
window from MainForm.Load.
Move your code (which is after Application.Run) into MainForm.Load.

Another way is to use threads as was suggested by other posters.

There are more advanced techniques of course, like creating message-only
window, which involves Win32 API (check HWND_MESSAGE - SetParent or
CreateWindowEx). Btw, this one could be used to transform your MainForm into
message-only window. It has some limitations, but could work for you too.

HTH
Alex

"Serge" <se**********@hotmail.com> wrote in message
news:3f**********************@reader0.news.skynet. be...
Thanks 100
That helps me a lot. I already read about this message loop a couple of time but now it's slowly all coming together.

Now just for the test I followed your suggestion and added the
Application.Run to my code so that the message loop would be started.
Specifically i added in my static Main method (from the class that is
defined as start object) the Application.Run line.
The problem I have here is that the code from Main method after the
Application.Run line is only executed when the form is closed again. And
that is not what I want.

I can not simply add this code in the form.
The reason for this is that this form is a simple status window.
It is shared by all my applications and contains no intelligent code. It
just displays the progress of the application.
The real work is done in the classes that are set as the start-up object.

So now I need a way to figure out how to start my application from my class and still start this form's message loop using the application.run line.
Do you know a way ?
I can think of some solution using delegates but don't know if this is the
best practise.

Thanks in advance for your suggestions,

Regards,

Serge
"100" <10*@100.com> wrote in message
news:%2****************@TK2MSFTNGP09.phx.gbl...
Hi Serge,

Application will hang for sure. When you use the Main method in Class1 as
a
start point. There is no code starting the message loop (Application.Run). At least Control.Invoke uses messages to switch the execution over the UI thread. Further more if there is no message loop you cannot move, resize, close or do anything with the form. Form is freezed on the screen. It

won't
even repaint itself.

What you might want to do is.
1. Remove
_frmStatus.Show();
_frmStatus.Refresh();
from the code. You don't need them.
2. Insted of
while(true)
{
Thread.Sleep(1000);
}

put the following:
System.Windows.Forms.Application.Run(_frmStatus);

That makes the code almost like the one you have in the form's class.

HTH
B\rgds
100

"Serge" <se**********@hotmail.com> wrote in message
news:3f***********************@reader3.news.skynet .be...
Hi,

I am having a thread hang problem in my c# code.

The example on the website: http://csharp.web1000.com/ is a
simplified version of my problem.

You will see in the form that a method TestThread increments a number in
the
textbox on the form.
TestThread is called from a worker thread (2nd thread) using a

TimerThread.
Every 2 seconds it will increment the number in te text box.

First start the project from the form (form1 class is the startup object). The Form is displayed. Now push the button, this will create the
TimerThread.
You now see nicely that the number increments every 2 seconds.

Now start the application from the class (class1 is the startup
object). Now the TimerThread will be created in the Class1 object.
You will see that the number is never incremented.

When stepping through the code you will see that the TestThread method

is called.
The TestThread code in the form properly detects that this is run from a second thread (line InvokeRequired) and continues to the line where Invoke is called. I use Invole so that the increment function would run on the forms thread. It is here where the application seems to hang. The

number in
the textbox is never incremented.

Can anyone explain me why this is happening or how to solve this ?
i was wondering, might this have something to do with

Apparementthreading
?
(this is used when you start the application from the form (=startup
object)).
Maybe when you start it from the class this is no longer the case ?
Maybe it's something completely different.
Thanks for shedding some light in the darkness.

Regards, Serge

http://csharp.web1000.com/



Nov 15 '05 #5
ok, got it

I now have my application working with the message pump running (using the
Application.Run) and my worker thread that I am able to configure
differently for each application (but re-using the status window)

Thanks VERY much !!!

"100" <10*@100.com> wrote in message
news:%2****************@tk2msftngp13.phx.gbl...
Hi Serge,
Yes, you are right. The code after Application Run will be executed only
after the main window (passed to Run method) as a parameter is closed. In
this case when the application is closed. You cannot have alive windwos in
Windwos without messeage loop to dispatch messages to it. What I want to say is all GUI applications has to have at least one UI thread (for windows
forms this is thread that eventually calls Application.Run) All UI
commponents has to be created by an UI thread.
What you might want to do in your case is to have 2 threads: one worker
thread and one UI thread to dispalay the status. See my code below.
The changes are:
1. I removed the Main method from Form1 class. We don't need it anymore.
2. I Added two new methods in Form1 class: Run and CloseForm(It could be
just Close, but I had to hide the base one).
3. Modified Class1's Main method.
4. I use the old timer to update the status form, but you can use whatever
fits better with your needs. The only things is that the changes you make to any UI components has to be made by the UI thread owning the component.
Which means that all threads but the UI thread itself has to use
Control.Invoke method.
//-------------------- Form1.cs -------------------------------//
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Threading;

namespace _ThreadTest
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
public System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox txtForm;
private System.Windows.Forms.Label label1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.txtForm = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// txtForm
//
this.txtForm.Enabled = false;
this.txtForm.Location = new System.Drawing.Point(8, 8);
this.txtForm.Name = "txtForm";
this.txtForm.Size = new System.Drawing.Size(48, 20);
this.txtForm.TabIndex = 0;
this.txtForm.Text = "0";
this.txtForm.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; //
// button1
//
this.button1.Location = new System.Drawing.Point(128, 8);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(192, 24);
this.button1.TabIndex = 1;
this.button1.Text = "Start Thread In Form Code - OK";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// label1
//
this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif",
7.764706F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label1.Location = new System.Drawing.Point(128, 8);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(184, 24);
this.label1.TabIndex = 2;
this.label1.Text = "Thread started from code = BAD";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(336, 36);
this.Controls.Add(this.button1);
this.Controls.Add(this.txtForm);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.Text = "Increment every 2 ses - thread test";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
public void Run()
{
Thread uiThread = new Thread(new ThreadStart(StatusThreadProc));
uiThread.ApartmentState = ApartmentState.STA;
uiThread.Start();
}
public void CloseForm()
{
if(InvokeRequired)
{
this.Invoke(new MethodInvoker(CloseForm));
}
this.Close();
}
/// <summary>Starts message loop (this thread is UI thread.)</summary>
public void StatusThreadProc()
{
Application.Run(this);
}

private void button1_Click(object sender, System.EventArgs e)
{
// Create the delegate that invokes methods for the timer.
TimerCallback timerDelegate = new TimerCallback(TestThread);

// Create a timer that waits one second, then invokes every second.
System.Threading.Timer timer = new System.Threading.Timer( timerDelegate, "nothing" ,1000, 2000);

}

public void TestThread(object state)
{
if (! this.InvokeRequired )
{
base.Refresh();
txtForm.Text = (int.Parse(txtForm.Text) + 1).ToString();
}
else
{
Invoke(new WaitCallback(TestThread), new object[] {state});
}
}
}
}
//-------------------------------
Class1.cs ----------------------------------------
using System;
using System.Threading;
namespace _ThreadTest
{
/// <summary>
/// Summary description for Class1.
/// </summary>
public class Class1
{
private static Form1 _frmStatus;
private static TimerCallback timerDelegate;
private static System.Threading.Timer timer;
public Class1()
{
}

[STAThread]
static void Main(string[] args)
{

_frmStatus = new Form1();
_frmStatus.button1.Visible = false;
_frmStatus.Run();

// Create the delegate that invokes methods for the timer.
timerDelegate = new TimerCallback(_frmStatus.TestThread);

// Create a timer that waits one second, then invokes every second.
timer = new System.Threading.Timer( timerDelegate, "nothing" ,1000,
10000);
for(int i = 0; i < 20; i++)
{
//Do some job
Thread.Sleep(1000);
}
//Stop the close the status form. (This will exit the UI thread).
_frmStatus.CloseForm();

//You can do more work here

}
}
}
HTH
B\rgds
100

Nov 15 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by Bruce Bon | last post: by
3 posts views Thread by Philippe C. Martin | last post: by
reply views Thread by pawo | last post: by
1 post views Thread by Serge | last post: by
4 posts views Thread by Mufasa | last post: by
1 post views Thread by CARIGAR | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.