Advanced Windows Form message priority / threading.

G

Guest

Hello again,
I've already placed a few posts on this topic.
This time i've a simple application that exhibits my problem,
I've placed sample solution 8k on my website should anyone be interested in
having a look. http://briankeating.net/transfer/test.zip

To recap the problem I expected (and found).
I've a main GUI thead (main form), this GUI thread has an UpdateTextBox
function that appends a string in a textbox and It also has a button that
stops my worker thread(s) form calling Invoke on main thead.

private void UpdateTextBox(string strText)
{
System.Diagnostics.Debug.Assert(InvokeRequired != true, "Invoke was
required", "calling begin invoke not on
the gui thread");
richTextBox1.Focus();
richTextBox1.AppendText(strText);
}

When my form loads I start two worker threads and these threads just loop
around and call Invoke on my main Form with a string to display.

private void ThreadEntryPoint()
{
while (!bStop)
{
string str = "Thread Id: " + GetHashCode() + ",\t" + nCount.ToString() + "
This is a passing string\r\n";

Invoke(new UpdateTextboxDelegate(UpdateTextBox), new object[] {str});
Interlocked.Increment(ref nCount);
//Thread.Sleep(1000); //slow sending
Thread.Sleep(10); //fast sending
} //end while

MessageBox.Show(Thread.CurrentThread.ToString() + " thread closing");
}

Now if my worker threads are slow sending i.e. I call Thread.Sleep(1000);
i.e. wait a seond between each invoke call on the gui thread, then I have no
problem I can click my button and the event handler is called

private void button1_Click(object sender, System.EventArgs e)
{
bStop = true;
}

However if my two threads are sending fast (only waiting 10 miliseconds)
then my GUI thread is so busy processing these update events that if i click
the stop button nothing happens.

.... Hope that kinda clears things up about a GUI thread becoming unresponsive.

So what are my options?
I'm thinking that Inovke is basically like SendMessage so maybe somehow i
can replace the windows message loop to do the following, (basically
prioritised message queue)
loop
peek all windows messages and process them, (get/dispatch)
then peek for one of my Inoke calls (get/dispatch)
endloop

Now people that have helped me already may be asking what has as this to do
with windows running in different threads, well the reason I want to do this
is, say for example i have 2 windows in my application, one window is busy
receiving messages from a worker thread (so this is gonna become
unresponsive), i wouldn't like all other windows to become unresponsive too),
switching between windows will require my busy thread to handle some window
messages (loose focus maybe etc) so a prioritised message queue will allow
this, hey maybe this is enough I'll keep at it and see what happens.

But I gues this post comes down to one question,
Is there anyway I can plug into a windows forms message queue and check for
pending invoke calls as described above?

Thanks for any help
Brian.

p.s.
This is only a sample test app, so it's not perfect for many a reason,
I realise the two worker threads calling Invoke is pretty much the same as
One worker thread calling invoke.
clicking close on the forms gets executed straight away for some reason
(maybe it's handled differently?)
Clicking close will throw an exception cause i havn't stopped the worker
thread(s) from sending.
 
G

Guest

I've been thinking about this a little more,
an call to Control.Invoke is basically a function all onto my Form (control)
from the ThreadPool,

If i want my Invoke calls in my message queue I prob have to use events? or
maybe PInvoke on SendMessage etc?
Hopefully these will arrive on my message que and I can introduce a
prioritised system?

thanks
Brian

Brian Keating EI9FXB said:
Hello again,
I've already placed a few posts on this topic.
This time i've a simple application that exhibits my problem,
I've placed sample solution 8k on my website should anyone be interested in
having a look. http://briankeating.net/transfer/test.zip

To recap the problem I expected (and found).
I've a main GUI thead (main form), this GUI thread has an UpdateTextBox
function that appends a string in a textbox and It also has a button that
stops my worker thread(s) form calling Invoke on main thead.

private void UpdateTextBox(string strText)
{
System.Diagnostics.Debug.Assert(InvokeRequired != true, "Invoke was
required", "calling begin invoke not on
the gui thread");
richTextBox1.Focus();
richTextBox1.AppendText(strText);
}

When my form loads I start two worker threads and these threads just loop
around and call Invoke on my main Form with a string to display.

private void ThreadEntryPoint()
{
while (!bStop)
{
string str = "Thread Id: " + GetHashCode() + ",\t" + nCount.ToString() + "
This is a passing string\r\n";

Invoke(new UpdateTextboxDelegate(UpdateTextBox), new object[] {str});
Interlocked.Increment(ref nCount);
//Thread.Sleep(1000); //slow sending
Thread.Sleep(10); //fast sending
} //end while

MessageBox.Show(Thread.CurrentThread.ToString() + " thread closing");
}

Now if my worker threads are slow sending i.e. I call Thread.Sleep(1000);
i.e. wait a seond between each invoke call on the gui thread, then I have no
problem I can click my button and the event handler is called

private void button1_Click(object sender, System.EventArgs e)
{
bStop = true;
}

However if my two threads are sending fast (only waiting 10 miliseconds)
then my GUI thread is so busy processing these update events that if i click
the stop button nothing happens.

... Hope that kinda clears things up about a GUI thread becoming unresponsive.

So what are my options?
I'm thinking that Inovke is basically like SendMessage so maybe somehow i
can replace the windows message loop to do the following, (basically
prioritised message queue)
loop
peek all windows messages and process them, (get/dispatch)
then peek for one of my Inoke calls (get/dispatch)
endloop

Now people that have helped me already may be asking what has as this to do
with windows running in different threads, well the reason I want to do this
is, say for example i have 2 windows in my application, one window is busy
receiving messages from a worker thread (so this is gonna become
unresponsive), i wouldn't like all other windows to become unresponsive too),
switching between windows will require my busy thread to handle some window
messages (loose focus maybe etc) so a prioritised message queue will allow
this, hey maybe this is enough I'll keep at it and see what happens.

But I gues this post comes down to one question,
Is there anyway I can plug into a windows forms message queue and check for
pending invoke calls as described above?

Thanks for any help
Brian.

p.s.
This is only a sample test app, so it's not perfect for many a reason,
I realise the two worker threads calling Invoke is pretty much the same as
One worker thread calling invoke.
clicking close on the forms gets executed straight away for some reason
(maybe it's handled differently?)
Clicking close will throw an exception cause i havn't stopped the worker
thread(s) from sending.
 
I

Ian Griffiths [C# MVP]

This may not seem like the most helpful of suggestions, but I think it's
pragmatic:

Don't do that!

Specifically, if you find yourself wanting to send messages to the UI thread
hundreds of times a second, that's probably a mistake. It's almost
certainly going to be better in such a situation to have a timer running on
the UI thread that periodically polls to see what has changed, and perform
updates if necessary.

This will solve the priority problem - the System.Windows.Forms.Timer class
uses Win32 windows timers, which send very low priority messages, so your
clicks will always take precedence.

It will also mean the system probably spends less time simply refreshing the
screen - it's always more efficient to do batched display updates than it is
to draw each and every update independently. In naive update
implementations you can find that you've actually spent most of your CPU
cycles repainting stuff, and very little time getting useful work done. The
user can only read updates so fast, so there's not much point trying to
update more than 10 times a second anyway. (Unless you're doing animation -
that's different. But for actual changes of information, even 10 updates a
second is probably more than is necessary.)

In short, sending hundreds (or even tens) of Invoke or BeginInvoke messages
to the UI thread every second is never going to be a useful thing to do.

As to what the *right* thing to do is... Well that depends on what you're
trying to achieve. Polling with a UI thread timer might be a good approach.
Or you might want to use some mechanism for throttling the rate at which you
deliver BeginInvoke calls - never queue up another one until the previous
one has been processed and never deliver them faster than some particular
rate, for example.


--
Ian Griffiths - http://www.interact-sw.co.uk/iangblog/
DevelopMentor - http://www.develop.com/

Brian Keating EI9FXB said:
Hello again,
I've already placed a few posts on this topic.
This time i've a simple application that exhibits my problem,
I've placed sample solution 8k on my website should anyone be interested
in
having a look. http://briankeating.net/transfer/test.zip

To recap the problem I expected (and found).
I've a main GUI thead (main form), this GUI thread has an UpdateTextBox
function that appends a string in a textbox and It also has a button that
stops my worker thread(s) form calling Invoke on main thead.

private void UpdateTextBox(string strText)
{
System.Diagnostics.Debug.Assert(InvokeRequired != true, "Invoke was
required", "calling begin invoke not on
the gui thread");
richTextBox1.Focus();
richTextBox1.AppendText(strText);
}

When my form loads I start two worker threads and these threads just loop
around and call Invoke on my main Form with a string to display.

private void ThreadEntryPoint()
{
while (!bStop)
{
string str = "Thread Id: " + GetHashCode() + ",\t" + nCount.ToString() + "
This is a passing string\r\n";

Invoke(new UpdateTextboxDelegate(UpdateTextBox), new object[] {str});
Interlocked.Increment(ref nCount);
//Thread.Sleep(1000); //slow sending
Thread.Sleep(10); //fast sending
} //end while

MessageBox.Show(Thread.CurrentThread.ToString() + " thread closing");
}

Now if my worker threads are slow sending i.e. I call Thread.Sleep(1000);
i.e. wait a seond between each invoke call on the gui thread, then I have
no
problem I can click my button and the event handler is called

private void button1_Click(object sender, System.EventArgs e)
{
bStop = true;
}

However if my two threads are sending fast (only waiting 10 miliseconds)
then my GUI thread is so busy processing these update events that if i
click
the stop button nothing happens.

... Hope that kinda clears things up about a GUI thread becoming
unresponsive.

So what are my options?
I'm thinking that Inovke is basically like SendMessage so maybe somehow i
can replace the windows message loop to do the following, (basically
prioritised message queue)
loop
peek all windows messages and process them, (get/dispatch)
then peek for one of my Inoke calls (get/dispatch)
endloop

Now people that have helped me already may be asking what has as this to
do
with windows running in different threads, well the reason I want to do
this
is, say for example i have 2 windows in my application, one window is busy
receiving messages from a worker thread (so this is gonna become
unresponsive), i wouldn't like all other windows to become unresponsive
too),
switching between windows will require my busy thread to handle some
window
messages (loose focus maybe etc) so a prioritised message queue will allow
this, hey maybe this is enough I'll keep at it and see what happens.

But I gues this post comes down to one question,
Is there anyway I can plug into a windows forms message queue and check
for
pending invoke calls as described above?

Thanks for any help
Brian.

p.s.
This is only a sample test app, so it's not perfect for many a reason,
I realise the two worker threads calling Invoke is pretty much the same as
One worker thread calling invoke.
clicking close on the forms gets executed straight away for some reason
(maybe it's handled differently?)
Clicking close will throw an exception cause i havn't stopped the worker
thread(s) from sending.
 
G

Guest

Hi Ian,

What can I say,

1) Thanks a million for spending the time to read that huge post
2) Great suggestion this approach makes a lot of sense.

Thanks again
Brian.

Ian Griffiths said:
This may not seem like the most helpful of suggestions, but I think it's
pragmatic:

Don't do that!

Specifically, if you find yourself wanting to send messages to the UI thread
hundreds of times a second, that's probably a mistake. It's almost
certainly going to be better in such a situation to have a timer running on
the UI thread that periodically polls to see what has changed, and perform
updates if necessary.

This will solve the priority problem - the System.Windows.Forms.Timer class
uses Win32 windows timers, which send very low priority messages, so your
clicks will always take precedence.

It will also mean the system probably spends less time simply refreshing the
screen - it's always more efficient to do batched display updates than it is
to draw each and every update independently. In naive update
implementations you can find that you've actually spent most of your CPU
cycles repainting stuff, and very little time getting useful work done. The
user can only read updates so fast, so there's not much point trying to
update more than 10 times a second anyway. (Unless you're doing animation -
that's different. But for actual changes of information, even 10 updates a
second is probably more than is necessary.)

In short, sending hundreds (or even tens) of Invoke or BeginInvoke messages
to the UI thread every second is never going to be a useful thing to do.

As to what the *right* thing to do is... Well that depends on what you're
trying to achieve. Polling with a UI thread timer might be a good approach.
Or you might want to use some mechanism for throttling the rate at which you
deliver BeginInvoke calls - never queue up another one until the previous
one has been processed and never deliver them faster than some particular
rate, for example.


--
Ian Griffiths - http://www.interact-sw.co.uk/iangblog/
DevelopMentor - http://www.develop.com/

Brian Keating EI9FXB said:
Hello again,
I've already placed a few posts on this topic.
This time i've a simple application that exhibits my problem,
I've placed sample solution 8k on my website should anyone be interested
in
having a look. http://briankeating.net/transfer/test.zip

To recap the problem I expected (and found).
I've a main GUI thead (main form), this GUI thread has an UpdateTextBox
function that appends a string in a textbox and It also has a button that
stops my worker thread(s) form calling Invoke on main thead.

private void UpdateTextBox(string strText)
{
System.Diagnostics.Debug.Assert(InvokeRequired != true, "Invoke was
required", "calling begin invoke not on
the gui thread");
richTextBox1.Focus();
richTextBox1.AppendText(strText);
}

When my form loads I start two worker threads and these threads just loop
around and call Invoke on my main Form with a string to display.

private void ThreadEntryPoint()
{
while (!bStop)
{
string str = "Thread Id: " + GetHashCode() + ",\t" + nCount.ToString() + "
This is a passing string\r\n";

Invoke(new UpdateTextboxDelegate(UpdateTextBox), new object[] {str});
Interlocked.Increment(ref nCount);
//Thread.Sleep(1000); //slow sending
Thread.Sleep(10); //fast sending
} //end while

MessageBox.Show(Thread.CurrentThread.ToString() + " thread closing");
}

Now if my worker threads are slow sending i.e. I call Thread.Sleep(1000);
i.e. wait a seond between each invoke call on the gui thread, then I have
no
problem I can click my button and the event handler is called

private void button1_Click(object sender, System.EventArgs e)
{
bStop = true;
}

However if my two threads are sending fast (only waiting 10 miliseconds)
then my GUI thread is so busy processing these update events that if i
click
the stop button nothing happens.

... Hope that kinda clears things up about a GUI thread becoming
unresponsive.

So what are my options?
I'm thinking that Inovke is basically like SendMessage so maybe somehow i
can replace the windows message loop to do the following, (basically
prioritised message queue)
loop
peek all windows messages and process them, (get/dispatch)
then peek for one of my Inoke calls (get/dispatch)
endloop

Now people that have helped me already may be asking what has as this to
do
with windows running in different threads, well the reason I want to do
this
is, say for example i have 2 windows in my application, one window is busy
receiving messages from a worker thread (so this is gonna become
unresponsive), i wouldn't like all other windows to become unresponsive
too),
switching between windows will require my busy thread to handle some
window
messages (loose focus maybe etc) so a prioritised message queue will allow
this, hey maybe this is enough I'll keep at it and see what happens.

But I gues this post comes down to one question,
Is there anyway I can plug into a windows forms message queue and check
for
pending invoke calls as described above?

Thanks for any help
Brian.

p.s.
This is only a sample test app, so it's not perfect for many a reason,
I realise the two worker threads calling Invoke is pretty much the same as
One worker thread calling invoke.
clicking close on the forms gets executed straight away for some reason
(maybe it's handled differently?)
Clicking close will throw an exception cause i havn't stopped the worker
thread(s) from sending.
 

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