How can i implement a message pump with winforms ?

N

nicolas.hilaire

Hi all,

i'm doing a quite long treatment in a function, and i'm showing the
progress of the treatment with a progressbar. The code is something
like this :

for each(entry in entries) // about 100 entries
{
TreatmentForOneOr2Secs();
this->progressBar1->PerformStep();
}


during the debug, the debugger tells me that :

Managed Debugging Assistant 'ContextSwitchDeadlock' has detected a
problem in 'd:\test\NetSendDotNet\debug\NetSendDotNet.exe'.
Additional Information: The CLR has been unable to transition from COM
context 0x189558 to COM context 0x189408 for 60 seconds. The thread
that owns the destination context/apartment is most likely either doing
a non pumping wait or processing a very long running operation without
pumping Windows messages. This situation generally has a negative
performance impact and may even lead to the application becoming non
responsive or memory usage accumulating continually over time. To avoid
this problem, all single threaded apartment (STA) threads should use
pumping wait primitives (such as CoWaitForMultipleHandles) and
routinely pump messages during long running operations.


Specially :
To avoid this problem, all single threaded apartment (STA) threads
should use pumping wait primitives (such as CoWaitForMultipleHandles)
and routinely pump messages during long running operations.

So, how can i pumping messages ? or, should i use a thread (and how ?)


Thanks for your help


Nicolas H.
 
G

Guest

Specially :
To avoid this problem, all single threaded apartment (STA) threads
should use pumping wait primitives (such as CoWaitForMultipleHandles)
and routinely pump messages during long running operations.
So, how can i pumping messages ? or, should i use a thread (and how ?)

A more elegant solution perhaps is to use a timer.
on each elapsed timer event, process one work item. this will give your
application the chance to perform aditional message processing in between
your own processing.

this also means that your overall processing will take longer, since you are
not continuously processing your own stuff.
using a separate thread will give you a bit better performance,but requires
more coding.

pumping messages inside a message handler is something i've never tried in
..NET, so I don't know if it is possible or not.

kind regards,
Bruno.
(e-mail address removed)
Remove only "_nos_pam"
 
W

Willy Denoyette [MVP]

Call routinely CurrentThread->Join(0), this implicitely calls
CoWaitForMultipleHandles and returns.

Willy.


| Hi all,
|
| i'm doing a quite long treatment in a function, and i'm showing the
| progress of the treatment with a progressbar. The code is something
| like this :
|
| for each(entry in entries) // about 100 entries
| {
| TreatmentForOneOr2Secs();
| this->progressBar1->PerformStep();
| }
|
|
| during the debug, the debugger tells me that :
|
| Managed Debugging Assistant 'ContextSwitchDeadlock' has detected a
| problem in 'd:\test\NetSendDotNet\debug\NetSendDotNet.exe'.
| Additional Information: The CLR has been unable to transition from COM
| context 0x189558 to COM context 0x189408 for 60 seconds. The thread
| that owns the destination context/apartment is most likely either doing
| a non pumping wait or processing a very long running operation without
| pumping Windows messages. This situation generally has a negative
| performance impact and may even lead to the application becoming non
| responsive or memory usage accumulating continually over time. To avoid
| this problem, all single threaded apartment (STA) threads should use
| pumping wait primitives (such as CoWaitForMultipleHandles) and
| routinely pump messages during long running operations.
|
|
| Specially :
| To avoid this problem, all single threaded apartment (STA) threads
| should use pumping wait primitives (such as CoWaitForMultipleHandles)
| and routinely pump messages during long running operations.
|
| So, how can i pumping messages ? or, should i use a thread (and how ?)
|
|
| Thanks for your help
|
|
| Nicolas H.
|
 
N

nicolas.hilaire

Call routinely CurrentThread->Join(0), this implicitely calls
CoWaitForMultipleHandles and returns.

Thanks willy, this is working and pumping message.
But on my form, i have a label and a progress bar.
During this time, the progress bar is refreshed, but not the label.
Should i call an explicit update ?

This is my code :
this->Show();
this->Update();
for each(entry in entries)
{
TreatmentForOneOr2Secs();
this->progressBar1->PerformStep();
System::Threading::Thread::CurrentThread->Join(0);
}
this->Hide();

("this" is the form)

Do you know why the label isn't refreshed ?

Thanks in advance

Nicolas
 
N

nicolas.hilaire

maybe it's better to use Invoke or BeginInvoke

what do you think about it ?


Best, Nicolas
 
C

Carl Daniel [VC++ MVP]

Willy said:
Call routinely CurrentThread->Join(0), this implicitely calls
CoWaitForMultipleHandles and returns.

Is this not what Application.DoEvents was made for?

Of course, performance will be better still if the work is done on a second
thread, with UI updates sent through Control.BeginInvoke.

-cd
 
N

nicolas.hilaire

Is this not what Application.DoEvents was made for?
Of course, performance will be better still if the work is done on a second
thread, with UI updates sent through Control.BeginInvoke.

I try to use BeginInvoke, but i can't undestand how it works !

I try to do something like this

ArrayList ^ GetList()
{
ArrayList ^ list = gcnew ArrayList();
BuildListInAThreadThatTakesTime();
return list;
}

Using Delegates and thread but i can't achieve to make it working,
because that's my first thread with the dotnet framework. If you know
how to do, or maybe a link that explains that, it will be great.

Otherwise, i will use
System::Threading::Thread::CurrentThread->Join(0);
and make a
label->update();

....

Best,

Nicolas
 
W

Willy Denoyette [MVP]

"Carl Daniel [VC++ MVP]" <[email protected]>
wrote in message | Willy Denoyette [MVP] wrote:
| > Call routinely CurrentThread->Join(0), this implicitely calls
| > CoWaitForMultipleHandles and returns.
|
| Is this not what Application.DoEvents was made for?
|
| Of course, performance will be better still if the work is done on a
second
| thread, with UI updates sent through Control.BeginInvoke.
|
| -cd
|
|
Not really, DoEvents was invented for VB and do pump the windows queue. The
managed wait services like Join() WaitOne() etc. do pump COM messages only
(CoWaitForMultipleHandles ), so this solves the OP's initial problem.
However, now I see he's running this long running procedure on the UI
thread, which is of course a NO NO in windows.

Willy.
 
W

Willy Denoyette [MVP]

| >Call routinely CurrentThread->Join(0), this implicitely calls
| >CoWaitForMultipleHandles and returns.
|
| >Willy.
|
| Thanks willy, this is working and pumping message.
| But on my form, i have a label and a progress bar.
| During this time, the progress bar is refreshed, but not the label.
| Should i call an explicit update ?
|
| This is my code :
| this->Show();
| this->Update();
| for each(entry in entries)
| {
| TreatmentForOneOr2Secs();
| this->progressBar1->PerformStep();
| System::Threading::Thread::CurrentThread->Join(0);
| }
| this->Hide();
|
| ("this" is the form)
|
| Do you know why the label isn't refreshed ?
|
| Thanks in advance
|
| Nicolas
|

That means you are running your long running task on the UI thread, this is
something you should not do, run this on another thread and call Invoke or
BeginInvoke to update the progressBar, that way your UI will remain
responsive.

Willy.
 
N

nicolas.hilaire

That means you are running your long running task on the UI thread, this is
something you should not do, run this on another thread and call Invoke or
BeginInvoke to update the progressBar, that way your UI will remain
responsive.

Yes, i'm running the task on the form class.

So, i'm going to use thread ... but, i just need something easy

something like this

Thread ^ t = gcnew Thread(gcnew ThreadStart(ThreadProcess));
t->Start();
WaitForTheThreadToTerminate();

Is this possible ? and how ?


Thanks for your help
 
W

Willy Denoyette [MVP]

| >That means you are running your long running task on the UI thread, this
is
| >something you should not do, run this on another thread and call Invoke
or
| >BeginInvoke to update the progressBar, that way your UI will remain
| >responsive.
|
| Yes, i'm running the task on the form class.
|
| So, i'm going to use thread ... but, i just need something easy
|
| something like this
|
| Thread ^ t = gcnew Thread(gcnew ThreadStart(ThreadProcess));
| t->Start();
| WaitForTheThreadToTerminate();
|
| Is this possible ? and how ?
|
|
| Thanks for your help
|


I would suggest you take some time to read the docs before you start using
multiple threads.
Anyway here is how you could init a background thread, probaly you must
initialize him to enter the STA as you seem to call into COM in your "task".

// in some handler (button click ??)

Thread ^ t = gcnew Thread(gcnew ThreadStart(this->MyLongRunningTask));
t.SetApartmentState = ApartmentState.STA; // see above
t.IsBackground = true;
t->Start();
// no need to wait for the thread to terminate!!
....


void MyLongRunningTask()
{
// keep the busy

}


Willy.
 
N

nicolas.hilaire

ok, i've tried this, but this is not working, as if the window is
frozen

I'm using ThreadPool and ManualResetEvent in my form class

Is this way of doing not good ?


System::Collections::ArrayList ^ getList()
{
list = gcnew System::Collections::ArrayList();
manualEvent = gcnew System::Threading::ManualResetEvent(false);
System::Threading::ThreadPool::QueueUserWorkItem(gcnew
System::Threading::WaitCallback(this,
&myNameSpace::frm_loading::ThreadProcess));
manualEvent->WaitOne();
return list;
}

void ThreadProcess(System::Object ^ stateInfo)
{
manualEvent->Reset();

this->progressBar1->Minimum = 0;
this->progressBar1->Maximum = nb;
this->progressBar1->Value = 0;
this->progressBar1->Step = 1;
this->Show();
this->Update();

for each (entry in entries)
{
TreatmentLongOnEntry();
this->progressBar1->PerformStep();
}
this->Hide();
manualEvent->Set();
}


How can i correct ?

Thanks in advance

Best regards,

Nicolas
 
N

nicolas.hilaire

I would suggest you take some time to read the docs before you start using
multiple threads.
Anyway here is how you could init a background thread, probaly you must
initialize him to enter the STA as you seem to call into COM in your "task".
// in some handler (button click ??)
Thread ^ t = gcnew Thread(gcnew ThreadStart(this->MyLongRunningTask));
t.SetApartmentState = ApartmentState.STA; // see above
t.IsBackground = true;
t->Start();
// no need to wait for the thread to terminate!!
...
void MyLongRunningTask()
{
// keep the busy

}

Thanks for your help,

In fact, i need to wait for the thread to finish, because, as you can
see in my last post, i'm returning a list, that is built in the
longTask function.

Regards
 
W

Willy Denoyette [MVP]

| >I would suggest you take some time to read the docs before you start
using
| >multiple threads.
| >Anyway here is how you could init a background thread, probaly you must
| >initialize him to enter the STA as you seem to call into COM in your
"task".
|
| >// in some handler (button click ??)
|
| > Thread ^ t = gcnew Thread(gcnew ThreadStart(this->MyLongRunningTask));
| > t.SetApartmentState = ApartmentState.STA; // see above
| > t.IsBackground = true;
| > t->Start();
| >// no need to wait for the thread to terminate!!
| >...
|
| >void MyLongRunningTask()
| >{
| >// keep the busy
| >
| >}
|
| Thanks for your help,
|
| In fact, i need to wait for the thread to finish, because, as you can
| see in my last post, i'm returning a list, that is built in the
| longTask function.
|
| Regards
|

No, Waiting on a UI thread means rendering the UI non-responsive. I guess
you need the list to update the UI, well do this from the non UI thread
using Control->Invoke or BeginInvoke.

Willy.
 
N

nicolas.hilaire

No, Waiting on a UI thread means rendering the UI non-responsive. I guess
you need the list to update the UI, well do this from the non UI thread
using Control->Invoke or BeginInvoke.

Hi again and thanks for your answer. I tryed to implement the method
using BeginInvoke. But, the UI is still quite frozen (my progressbar is
refreshing, but the entire form is not). And when i put an other
application on top of the z-order, i can't go back to my window, during
the long task.

This is my code, i hope you can find why it's not working (I'm calling
the method getList(), that constructs a list, shows a form with a
progress bar during the construction, and returns me the list at the
end)


System::Collections::ArrayList ^ getList ()
{
list = gcnew System::Collections::ArrayList();
int nb = 40;
this->progressBar1->Visible = true;
this->progressBar1->Minimum = 0;
this->progressBar1->Maximum = nb;
this->progressBar1->Value = 0;
this->progressBar1->Step = 1;
this->Show();
this->Update();
System::IAsyncResult ^ res;

res = this->BeginInvoke(gcnew InvokeMethod(this,
&myProject::frm_loading::UpdateProgressBar), nullptr);
this->EndInvoke(res);
System::Threading::Thread::Sleep(1000);
this->Hide();

return list;
}

private:
void UpdateProgressBar(void)
{

for (int i=0;i<40;i++)
{
list->Add(System::Convert::ToString(i));
this->progressBar1->PerformStep();
System::Threading::Thread::Sleep(500);
}

}


Thanks a lot in advance
 
W

Willy Denoyette [MVP]

I don't see any thread creation in the code you posted, is getList() your
thread procedure?
Also, you don't need to call EndInvoke after a BeginInvoke call. I also
don't get why you are calling Sleep either.

Willy.


| >No, Waiting on a UI thread means rendering the UI non-responsive. I guess
| >you need the list to update the UI, well do this from the non UI thread
| >using Control->Invoke or BeginInvoke.
|
| Hi again and thanks for your answer. I tryed to implement the method
| using BeginInvoke. But, the UI is still quite frozen (my progressbar is
| refreshing, but the entire form is not). And when i put an other
| application on top of the z-order, i can't go back to my window, during
| the long task.
|
| This is my code, i hope you can find why it's not working (I'm calling
| the method getList(), that constructs a list, shows a form with a
| progress bar during the construction, and returns me the list at the
| end)
|
|
| System::Collections::ArrayList ^ getList ()
| {
| list = gcnew System::Collections::ArrayList();
| int nb = 40;
| this->progressBar1->Visible = true;
| this->progressBar1->Minimum = 0;
| this->progressBar1->Maximum = nb;
| this->progressBar1->Value = 0;
| this->progressBar1->Step = 1;
| this->Show();
| this->Update();
| System::IAsyncResult ^ res;
|
| res = this->BeginInvoke(gcnew InvokeMethod(this,
| &myProject::frm_loading::UpdateProgressBar), nullptr);
| this->EndInvoke(res);
| System::Threading::Thread::Sleep(1000);
| this->Hide();
|
| return list;
| }
|
| private:
| void UpdateProgressBar(void)
| {
|
| for (int i=0;i<40;i++)
| {
| list->Add(System::Convert::ToString(i));
| this->progressBar1->PerformStep();
| System::Threading::Thread::Sleep(500);
| }
|
| }
|
|
| Thanks a lot in advance
|
 
N

nicolas.hilaire

I don't see any thread creation in the code you posted, is getList() your
thread procedure?
Also, you don't need to call EndInvoke after a BeginInvoke call. I also
don't get why you are calling Sleep either.

Thanks again for helping me Willy,

I finally changed my way of doing this.

I use the ability of a form to be modal (by calling ShowDialog instead
of Show), then i don't have to care about waiting for the end of the
task.

I'm doing the init in the form_load, then i start a thread, that
perform the long task and update the UI.

At the end of the thread, i'm calling the method close() of the form,
then i came back just after the ShowDialog and i'm getting the list
from the form.
I suppose i can do this, because i didn't dispose the ressources of the
form, right ?


This is now working,
thanks a lot for your help.


Best regards,
Nicolas
 
T

taylorjonl

*>I don't see any thread creation in the code you posted, is
getList() your


Thanks again for helping me Willy,

I finally changed my way of doing this.

I use the ability of a form to be modal (by calling ShowDialog
instead
of Show), then i don't have to care about waiting for the end of the
task.

I'm doing the init in the form_load, then i start a thread, that
perform the long task and update the UI.

At the end of the thread, i'm calling the method close() of the
form,
then i came back just after the ShowDialog and i'm getting the list
from the form.
I suppose i can do this, because i didn't dispose the ressources of
the
form, right ?


This is now working,
thanks a lot for your help.


Best regards,
Nicolas *

I know this is old but it came up in my googling and figured I would
finish it off in case anyone reads it and doesn't understand.

I think the OP is missing the concept of not blocking a UI thread. I
will try to straighten it out.

When you register for a UI event, such as a button's click event, you
don't want to do any operations that are long, and you don't want to
block(sleep,pause, wait) in that function. The reason is that this
callback was performed on the UI's main thread and the UI will not
respond during this time. Instead you should create a worker thread.
I will post some code below, it will be in C# since that is my most
familiar language.


Code:
--------------------
public void OnButtonClick( object sender, EventArgs args )
{
Thread.Sleep( 10000 ); <---- BAD, Blocking UI thread
SuperLongCPUIntensiveCall(); <---- BAD, Blocking UI thread
}
--------------------


The above is bad, and will block UI events. Instead you should create
a call that will run on a thread in the background.


Code:
--------------------
public void OnButtonClick( object sender, EventArgs args )
{
new Thread( SuperLongCPUIntensiveCall() ).Start();
}
--------------------


The OP was doing the following.


Code:
--------------------
public void OnButtonClick( object sender, EventArgs args )
{
new Thread( SuperLongCPUIntensiveCall() ).Start();
manualEvent.WaitOne();
}

public void SuperLongCPUIntensiveCall()
{
manualEvent.Reset();
// DO A TON OF WORK
manualEvent.Set();
}
--------------------


That is the same as making the call on the UI thread, actually it is
slower, you are still blocking the UI thread. If you have to define an
additional function that will be started on a background thread then do
it, just don't ever do CPU intensive or blocking calls on a UI thread.
 

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