By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,267 Members | 1,808 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,267 IT Pros & Developers. It's quick & easy.

Periodic problem in InitializeComponent of modal form with a forms.timer

P: n/a
Hi,

I have a periodic problem which I am having a real time trying to sort.

Background:
An MDI VB app with a DB on SQL 2000.
I have wrapped all the DB access into an object which spawns a thread to
access the database and then displays a modal dialog which allows the user
to cancel the task, if it is taking longer than they want, and shows them a
display of how long the query has been running so far.

I have been very careful (I think!) to make sure that the UI is only ever
updated from the main UI thread. I pass status info from the SQL therad to
the UI thread through a System.Threading.AutoResetEvent.
A system.windows.forms.timer runs in the Modal form to update a textbox with
the amount of time it has been there and to check the 'SQL finished' event
above.

Everything work fine 99.9% of the time BUT, very occasionally, I get an odd
situation in InitializeComponent in the modal form.
As far as I can ascertain (sorry, that should be, totally guess!), when the
timer is enabled, it does not 'see' the containing forms message loop and so
it instantiates one itself (?). This new message loop 'sees' messages in the
MDI's queue including the pending message currently being processed which
caused this whole event to occur (stay with me here!)

I think that this makes much more sense in the context of a real stack
trace:

Stack Trace: at System.Data.SqlClient.SqlCommand.ValidateCommand(S tring
method, Boolean executing)
at System.Data.SqlClient.SqlCommand.ExecuteReader(Com mandBehavior
cmdBehavior, RunBehavior runBehavior, Boolean returnStream)
at System.Data.SqlClient.SqlCommand.ExecuteReader()
at Ideal.clsDBThread.SQLFetchThread()
Current Stack: at System.Environment.GetStackTrace(Exception e)
at System.Environment.GetStackTrace(Exception e)
at System.Environment.get_StackTrace()
at Ideal.basUtility.LogError(Exception e, String strUserMsg)
at Ideal.clsDatabase.SQLFetch(String strCommand)
at Ideal.clsDatabase.TryEditLock(Int32 iDealID)
5 at Ideal.frmDeal.cmdEdit_Click(Object sender, EventArgs e)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventAr gs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons
button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage (Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(M essage& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg,
IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchM essageW(MSG& msg)
at
System.Windows.Forms.ComponentManager.System.Windo ws.Forms.UnsafeNativeMetho
ds+IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason,
Int32 pvLoopData)
at System.Windows.Forms.ThreadContext.RunMessageLoopI nner(Int32 reason,
ApplicationContext context)
4 at System.Windows.Forms.ThreadContext.RunMessageLoop( Int32 reason,
ApplicationContext context)
3 at System.Windows.Forms.Timer.set_Enabled(Boolean value)
at System.Windows.Forms.Timer.set_Interval(Int32 value)
2 at Ideal.frmDBExec.InitializeComponent()
at Ideal.frmDBExec..ctor()
at Ideal.clsDatabase.SQLFetch(String strCommand)
at Ideal.clsDatabase.TryEditLock(Int32 iDealID)
1 at Ideal.frmDeal.cmdEdit_Click(Object sender, EventArgs e)
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventAr gs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons
button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage (Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(M essage& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg,
IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchM essageW(MSG& msg)
at
System.Windows.Forms.ComponentManager.System.Windo ws.Forms.UnsafeNativeMetho
ds+IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason,
Int32 pvLoopData)
at System.Windows.Forms.ThreadContext.RunMessageLoopI nner(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.ThreadContext.RunMessageLoop( Int32 reason,
ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at Ideal.basMain.Main()

From the bottom.
Normal appication stack (I think) with a mouse click being processed
At point (1) the routine which handles the button click is called
This calls some SQL which causes the spawned thread/Modal dialog combination
and the modal dialog (Initialisation call can be seen at point 2)
Within this initialisation the timer interval gets set which in turn enables
the timer (point 3). All normal so far
Then:
At point (4), within the timer enable, there is a call to RunMessageLoop
which (I think) hooks onto the MDI's context and picks up the same mouse
click that we are currently processing and recalls the button click routine!
(point 5)

Any help or pointers to help would be VERY VERY apprieciated

Thanks in advance

Stephen
Nov 21 '05 #1
Share this Question
Share on Google+
8 Replies


P: n/a
Stephen,

In my mind do you need with a problem as yours all the source before your
eyes.

However the first answer on your question is simple. For multithreaded
applications should the forms timer not be used.

There is the threading timer (for me a terrible thing comparing to that easy
forms timer because it is difficult to stop). However it is made specialy
for threading, therefore I would in your place first look for that.

http://msdn.microsoft.com/library/de...ClassTopic.asp

I hope this helps?

Cor
Nov 21 '05 #2

P: n/a
Hi Cor,

Thanks very much for you suggestion.

Unfortunately, I think that using a system.Threading.Timer might cause more
problems rather than solve them? In the MSDN docs they say (About the
TimerCallback) 'The method does not execute in the thread that created the
timer; it executes in a thread pool thread supplied by the system'
The reason for the timer is to update the UI to show how long the task has
been running and so needs to run in the UI's own thread.

Also, although the windows.forms.timer is not thread safe, it is never
accessed from any other thread than the UI one (I hope) and so I don't think
that this will be an issue (as far as I understand the way that the timer is
working?)

I am sure you are right that it is a threading issue, because of the
periodic nature, but I can't for the life of me see where the 'unsafe'
access is going on.

Hmmm.

One other problem I have is that this happens so infrequently that I havn't
been able to recreate the problem myself in a debug environment. All I have
to work from are logs that I have got all the clients to create.

Stephen

"Cor Ligthert" <no************@planet.nl> wrote in message
news:OW**************@TK2MSFTNGP14.phx.gbl...
Stephen,

In my mind do you need with a problem as yours all the source before your
eyes.

However the first answer on your question is simple. For multithreaded
applications should the forms timer not be used.

There is the threading timer (for me a terrible thing comparing to that easy forms timer because it is difficult to stop). However it is made specialy
for threading, therefore I would in your place first look for that.

http://msdn.microsoft.com/library/de...ClassTopic.asp
I hope this helps?

Cor

Nov 21 '05 #3

P: n/a
Stephen,

You mean that what you are doing is

Starting a modal form with a timer as a clock in it and a button
Start in that modal form a thread to read something
Abort that thread when the user pushes the button (when it is not ready)

Cor
Nov 21 '05 #4

P: n/a
Hi Cor,

Yes (but with the following very slight 'frills')

In the main app, start a thread to run the SQL command
Do a 'WaitOne' on a 'SQL thread finished' event with a timeout of three
seconds
If the event did not fire within the three seconds, display a modal dialog
with a 'clock' and a cancel button (I wait for up to three seconds before
doing this so that the, majority, of requests which take less than three
seconds do not have the overhead of creating the dialog and if any user
wants to cancel the SQL task within three seconds they should be shot for
being so impatient!)

The timer tick event first checks for the SQL thread having finished by
doing a very short 'WaitOne' on the event above and then either closes the
dialog with a me.Close if it has or updates a 'clock' label.

If the Cancel button is clicked, it cancels the SqlCommand and then does a
Thread.Join to wait for the DB thread finishing before doing a me.Close.

The main app which created modal dialog does a .Dispose on the dialog form
object when it returns to make sure that the timer is cleaned up.

Thanks again.

Stephen

"Cor Ligthert" <no************@planet.nl> wrote in message
news:OX**************@TK2MSFTNGP15.phx.gbl...
Stephen,

You mean that what you are doing is

Starting a modal form with a timer as a clock in it and a button
Start in that modal form a thread to read something
Abort that thread when the user pushes the button (when it is not ready)

Cor

Nov 21 '05 #5

P: n/a
Stephen

And when you do it as I wrote, what does that mean. The reference too a
dataset is the most simple thing there can be (assuming you are using a
dataset).

Cor
Nov 21 '05 #6

P: n/a
Hi Cor,

I'm really sorry. I am not quite sure what you mean.
Do you mean your suggestion to use the Threading.Timer?

"Cor Ligthert" <no************@planet.nl> wrote in message
news:ev****************@TK2MSFTNGP15.phx.gbl...
Stephen

And when you do it as I wrote, what does that mean. The reference too a
dataset is the most simple thing there can be (assuming you are using a
dataset).

Cor

Nov 21 '05 #7

P: n/a
Stephen,

I mean to start all dataretrival actions from your model form (in that
thread)

Not that I ever tried it, however when I saw you problem I thought why not.

What you want is to get a dataset (I still assume) and in the meantime the
user may (after a shortwhile) only do one thing and that is stop it, what
can be done in that modal form.

Cor
Nov 21 '05 #8

P: n/a
Cor,

Right. (Sorry) I see totally what you mean.

Actually, this is how I had things set up for a very short while when I was
developing it.
The only thing I have against this is that it means the modal form will pop
up for every SQL access which means you can get quite a large number of
popup/disappearing dialogs. Which is A) fairly ugly and B) slows the UI down
a fair amount.

Anoyingly, because I, so far, havn't found a way of forcing the error to
occur, I havn't got an easy way of testing if this does alleviate the
problem.

I think that I will spend a bit of time writing a test prog to fire requests
to the DB one after another and see if I can get the error to occur myself
and then try you suggestion to see if it gets rid of it.

If you have any other thoughts in the mean time. Please give me a shout!

Thanks

Stephen

"Cor Ligthert" <no************@planet.nl> wrote in message
news:O3****************@TK2MSFTNGP12.phx.gbl...
Stephen,

I mean to start all dataretrival actions from your model form (in that
thread)

Not that I ever tried it, however when I saw you problem I thought why not.
What you want is to get a dataset (I still assume) and in the meantime the
user may (after a shortwhile) only do one thing and that is stop it, what
can be done in that modal form.

Cor

Nov 21 '05 #9

This discussion thread is closed

Replies have been disabled for this discussion.