Home » VB.NetRSS

Why To Not Use Threading.Sleep in Your Application

First of all, I hope that everyone who is interested joins in this conversation especially SJ, Carsten, Spotty, Andreas and Nobugz.

Experienced developers here often see new developers experiencing difficulty after calling Threading.Sleep and more experienced developers take issue with its use but rarely is there ever a comprehensive explanation for that. I thought I’d start a thread on this with background as to why we say these things. First of all some background information is needed.

In Windows operating systems, when one runs a process, they are starting a process. A process is a contextual environment for a program and it will allow a program to call the things it needs to run. These aspects of a process are kept fairly transparent to a developer but a process has properties external and internal to it. Externally, a process needs to send and receive messages so that controls (including forms) can behave as expected. Internally, transparent to basic developers there are message pumps for dispatching these messages to a users code and controls. A basic property that is expected of a process is that it be able to send and receive these messages which enable Windows to work. Threading.Sleep disables that ability. Often we see upset users who have strange problems who have just called Sleep. “Sleep” disables a process ability to respond to anything internally or externally for the duration of Sleep call. Fundamentally then, a basic principle of a windows environment is that it is event driven and sleep disables the ability to process any and all events. Symptoms will be controls not working and forms not updating.

Often the new developer wants to wait on something and they call sleep and because the basic properties of a process have been altered, the new user see unexpected results.

Here is a design often seen here:

Private Sub PD()

While Not ConditionUser Loop

‘Process Data
‘Process Data
Sleep

If SomeCondition then Condition = true

End while

There is a strong desire on the part of the beginner to want to use sleep to manage basic design flaws which disables a programs ability to respond to internal messages and events. Beyond the process put into sleep states inability to respond to low Level GUI messages, the process also cannot respond to timers.

In other Operating systems there are states analogous to Sleep which is not as severe. A process can wake up to handle asynchronous execution so you might see designs analogous to this:

Subroutine Main()

Hibernate

End Sub

ASynchronousHandler1

End Sub

ASynchronousHandler2

End Sub

Such a program is immediately put to sleep and when there is the delivery of an asynchronous event, it’s processed and the process goes back to sleep. The event could be a timer expiration or I/O completion etc. This architecture is useful for a program that handles something and then goes back to sleep. In other words, it’s the basic design for a server. There is no analogous state in Dot Net and hence other techniques are used. This discussion would not be meaningful without offering models for the proper way code deal with issues like these:

Class Whatever

Protected Structure Wood

Public Arg1 as integer
Public Arg2 as Integer

End Structure

Private Wood1 as Wood

Protected friend withevents tmr as new System.Windows.Forms.Timer

Form1_load (ByVal sender AsObject, ByVal e As System.EventArgs) _
Handles Form1.load

    Tmr.stop
       tmr.interval = 250 ‘ one quarter of second interval

‘ Your load code

End Sub

Private Sub ProcessData(ArgA, Argb, ArgC)

Wood1 = new wood

Wood1.Arg1 = ArgA ‘ pack up data to process (Context)
Wood1.Arg2 = ArgB

Tmr.Start

End Sub

Private Sub Tmr_Tick (ByVal sender AsObject, ByVal e As System.EventArgs) _
Handles Tmr.Tic

Tmr.stop

‘Unpack the data and process it

‘ From the data determine if we are finished

If Finshed then CompletionRoutine(wood1) else Tmr.Start

Return

End Sub


Private Sub CompletionRoutine(Wood1 as Wood)

‘resume whatever you need to do

End Sub

End Class

This way the process never goes to sleep and remains responsive to users and data. With alittle added complexity much is gained. I’ve written over one hundred thousands lines of Dot net and have only used Sleep once. It was in a toolbar which moved itself. The effect I wanted was a gliding effect so I’d move the toolbar a couple of pixels and sleep for a few milliseconds, schieving exactly the effect I wanted. But here is what often turns up in this forum:

Private Subroutine Foo()

WebBrowser.Nagivate(“www.foo.com”)
While Not WebBrowser.DocumentComplete

Sleep (50)

End While

‘Continue processing

End Sub

This is REALLY BAD code. What if the URL is not there or it times out?This process will never wakeup and sit like the rock of Gibraltar on your desktop until you kill it with Task Manager. Here, the user should have used an event:

Private Subroutine Foo()

WebBrowser.Nagivate(“www.foo.com”)

End Sub

Private Sub WebBrowser_NavigationComplete(ByVal sender AsObject, _
ByVal e As System.NavigationEventArgs) _
Handles WbBrowser.NaVigationComplete

‘Process the data and continue

End Sub

I’ve come to see calling Threading.Sleep is having strayed into a fundamental design error, the possibility that a developer does not understand event handlers or they have missed a control or a component's events.

 

84 Answers Found

 

Answer 1

I just wanted to say thank you reneec

I really appreciate the explanation,  i would really like to see more info on other points as well.

So many times i see - don't do this or don't do that.  And the answer although really long, does not quite explain why.

And that may also be because the answer is over out heads.

This thread  is a perfect example for many:  it shows you what you shouldn't do and now here is how you should do it.

And why not to do it is explained very well.

And even better it has "Real World" examples.

Wonderful

Many times i feel like the knowledge that you more experienced  programmers have is just sitting idle and teased by throwing simple code  bits at us.  Which many times that's what were askin for.  And even though it gets you to the next point, many don't even know how or why it works.  It just does.  And i see the frustration all the more experienced have when us beginners just don't get it.  Even though the answer you gave is the right one, we are still looking for the answer even though you gave it because we just don't understand how to put  it together.

Thanks again, hope  to see more.

 

Answer 2

Hi JS06,

Perhaps this thread  may give us a chance to talk about more than just Sleep? I’m a Crone meaning I’m over fifty and I’ve been a Crone for ten years now. That doesn’t mean much other than I’ve had a chance to acquire a historical perspective after seeing generational differences. I’ve often wondered about what technology has done for us because we’ve produced a generation who looks toward instant gratification. Beyond the wider social commentary, this has to do with the frustrations you’ve referred to and I think there get’s to be a lot of frustration at times.

Sometimes I feel overwhelmed when I see someone come in take on some of the things  they do. it’s  like, “I just tasted my first cheeseburger at McDonalds and I really want to fix a Julia Childs seventeen course dinner.” If you look closely, there are an awful lot of fundamentals in cooking ala Julia Child’s. I also stress fundamentals because you absolutely need to know them. You can’t make a cheeseburger if you don’t know what cheese is.

Needless to say there is an enormity of depth to know in all of this and I see where I shall be a student forever. But I will always have the fundamentals to fall back  on when I’m interpreting whatever is new in front of me. This is why I stress fundamentals such as datatypes. There’s another secret I’ve discovered. It’s not the answers you have, it’s the questions you can generate to find a meaningful  answer.

Returning to the frustrations, you’re right it has to be frustrating to get half way answers. But to get full answers on question could require a post as long as my first post each time someone asks the same question and yet we see sleep  induced problems  many times a week here. One cannot post an answer like that over and over. So the answer is discussions like this one that we can point to as many times as the question is asked which should reduce a lot of the frustrations at least I hope  it should.

I’ve tried to do the same for lessons on how to use the debugger. New developers  often seem to be shy of the debugger. More experienced  developers need to encourage it’s use instead of message  boxes. But yes… I’d love to see more of these discussions.

And JS06… thank you!

 

Answer 3

Actually, I have been tempted to post a thread  like this about the abused functions Sleep and CreateGraphichs, but from the opposite point of view!

Unlike many others, I do not regard these functions as bad design. It is correct that Sleep blocks the thread from which it is called, but if it is a background  thread it doesn't matter. If it is the UI thread, things  are not just black and white. By default, the UI thread has higher priority than background threads and thread pool threads, so Sleep may be necessary to allow a job on a low  priority thread to finish. For example, if you want to change a serial port, you need to close the old port and open a new one. However, you must give the system  time to close down the background thread for the old port before creating a new thread for the new port, and the easiest way to do this is to block the high priority UI thread temporary by means of Sleep! In a background thread you can also use Sleep(0) to release the CPU if you cannot utilize the rest of the time slot. Besides, Windoze is so slow that blocking the UI thread for e.g. 200 mS doesn't really matter. If you call  Application.DoEvents() to empty the message  queue before the Sleep command, nobody will notice, and you may save a lot of programming and resources (timers etc.). Besides ReneeC, you are a little wrong. Sleep will not block the process  ability to do anything as you write - just the thread from which it is called. This makes quite a difference.

Now the cork is off the bottle - I do not regard CreateGraphics as bad design  either. The true  teaching is just to call Invalidate() every time just a single pixel has been changed and therefore redraw the entire form, which of course takes time and create flicker if you do not use double buffering. It is correct that Windows (unlike the old Amiga) is not intelligent enough to repaint a window automatically if it e.g. has been covered by another window, so you must have a handler for the Paint event, which can do this, but you may need to draw hundreds of pixels per second, but only act on the paint event  very seldomly. Actually, the vertical bargraph thread  http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1539826&SiteID=1 is a very good example of the two ways of doing things. As Albert Einstein says: Everything should be made as simple as possible, but not simpler!

So my point is: It is OK to use all functions - you should just know what you are doing!

ReneeC

Your debugger thread was excellent, but much too fast digged down in the archive. Unfortunately, this forum does not have a place to put  links to useful knowledge. I have also answered the same questions over and over again about the serial port - the only thing I really know something about in VB. Therefore, I have put all my knowledge on the knowledgebase on our homepage http://www.innovatic.dk/knowledg.htm. If you can rewrite your thread in one article suitable for a knowledgebase, I can put it in our's if you cannot find a better, more software oriented place to put it. Our knowledgebase primary focus on process control.

 

Answer 4

Renee,

The idea that the Dot Net environment  is event  driven is, conceptually, very clear and powerful.

In practice, though, it is not so well behaved.

Your code,

Private Subroutine Foo()

WebBrowser.Nagivate(“www.foo.com”)

End Sub

Private Sub WebBrowser_NavigationComplete(ByVal sender  AsObject, _
ByVal e As System.NavigationEventArgs) _
Handles WbBrowser.NaVigationComplete

‘Process the data  and continue

End Sub

does not work  for websites made of frames. The NavigationComplete or Document Complete events  won't capture the final loading of the page.

You have to resort to sleeping the thread

 

Answer 5

It's pretty well known that the webbrowser is not without problems. I've done a tabbed webbrowser in fact I'm typing on it now to you. It does frames fine and I promise you there is no Threading.sleep in the code. I've used it for a year now and and I've never seen a problem in it with framed pages.

Could you point me to a page where you say I'd have problems?

It does absolutely fine on these pages:

http://victorian.fortunecity.com/brambles/4/frames/

http://hem.passagen.se/ceel/frames/frames.htm

Carsten,

I've written mainframe disk drivers so of course I understand multi-threading. Because I've written mainframe disk drivers which was also a Cutler operating  system, I find the multithreading environment  so restrictive that I have never used it. You might be right and who could object  to sleep(0) but I really can't comment on that environment since I've never played in it. At any rate, here people are not having problems  at that level.

 

Answer 6

ReneeC

The multithreading system  of .NET is restrictive, but it has one advantage - it is very simple and easy to overlook. I truely believe that preemptive multithreading (time sliced) is something the devil has created when he was in a really bad mood, but the .NET version is really not that bad. Maybe you should start  using it?

 

Answer 7

I'll use it when I need to calculate prime numbers from here to the moon. Given the dis/ease of threads being able to talk to controls  not owned by that thread, I  don't find the multithreading all that useable and have always been critical of that.

In all honestly if I ever had a situation where computation needs impacted the responsiveness of the UI, of course I'd use it, but that's not really the kind of computing that I do so it has not been an issues. I've used multithreading to create multi-core loads and good ones at that, but that's about all.

In anything but a single task computer with no OS, there is going to be timeslicing of some kind whether it's round robining or the servicing of hardware interrupts, it's going to happen and at the applications level  it's transparent  so I don't woory about it just as I didn't worry about it in my mainframe drivers because it's an inevitability.

 

Answer 8

I am certainly not trying to dodge the question, but all the examples of pages with frames that give me problems  with the documentcomplete event  are behind passwords and thus, I cannot share. If I remember or find others that can be shared I will let you know.
 

Answer 9

Please do. My browser is not without problems  but they are in areas where there are known and reported bugs. I have never seen my browser act up in the the situations you describe.

 

Answer 10

ReneeC

The reason why I don't like preemptive task/thread swithing is because of the very low  efficiency. Because you never know when you loose the CPU, all arguments for methods have to be transferred by value instead of by reference. What happens in today's computers is basically an endless data  copying, which also leads to a serious fragmentation of the memory. The real payload is rather limited. Every time you want to do something, data is copied to and from the stack or heap, and each delegate need its own invoke methods to hold the arguments.

I have completely other visions for the future OS and computer world, which you can read more about on our homepage. If all tasks are atomic with a maximum execution  time of 1 mS (100 uS for high priority) and everything takes place in the right order, you don't need to copy anything!

 

Answer 11

" have completely other visions for the future OS and computer world, which you can read more about on our homepage."

My vision is not for a better OS because you can't have one on the Intel Architecture. Remember when Carl Sagan came out with "The Dragons of Eden"? He talked about the reptillian brain in humans. Well from a hardware pov, we are still executing the remnants of 8086s. It's true.

Poor Cutler coming from a VAX architecture  for which he designed the instruction set, to the Intel platform. You speak of problems  with context switching. The VAX did a context switch with one instruction designed for OS context switching. Memory on the Vax was "scatter/gather". That is to say that memory mamangement was a mixture of hardware and software where every process  had a contiguous address space, user, supervisor, Executive and Kernal Stacks from the bottom to the top of four gigs. Certainly it had 32 software priorities and also hardware IPLs with their own address vectors and a basic  and a most elegant instruction set of 400 instructions.

You won't have a good operating  system until there is an equally good platform architecture for it to run  on. The Vax did not have to copy anything to do a context switch, nor was there any fragmentation of memory.

Atomicity is a complex topic of course. Some instructions were atomic and some weren't. When you code  in assembler you have to know what was what. There were also Movc3 and movc5 instructions used for both paging and buffer copies. There were non-atomic instructions if I remember correctly.  But at high IPL's it didn't make any difference because you weren't going to be interrupted or if you were, your context would be there when the instruction resumed because of the stack architecture and the way the stack was used. Also at high IPLs you were working  with non-paged pool. There was no paging.

 

Answer 12

ReneeC

I couldn't agree more with you about the hopeless Intel architecture  (just see my answer to Tall Dude in the thread: "A question about programming languages in general" http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1881611&SiteID=1) - that's why we also have a suggestion for a new microprocessor architecture on our homepage  !

When I talk about atomic I just mean program parts with a maximum execution  time of 1 mS - not single assembler instructions. I know that you really "burn" for operating  systems, but try to ask yourself the question: What do you need an OS for? You have only one CPU (normally), so at any time you can only run one part  of your code. Contemporary execution is just an illusion. Suppose no routine was allowed to run  for longer time than the interrupt latency, that is, approximately 1 mS, before it returns or waits for something (passive state). Then you did not have to cut any program  (preemptive, time sliced switching) and you would not need any Deferred Procedure Calls. Everything would be reduced to a question about priorities. So instead of having multiple threads, which requires an enoumous amount of resources, you would only need two or three priority levels with a queue for each. All programs  with the same priority could share the same thread. Even high priority interrupts could be executed as normal high priority jobs with a maximum execution time of e.g. 50 uS, so it would be much easier to write drivers as this could be done as any other program - just with a higher priority. If you don't put  a routine on a queue if it is there already, it is guaranteed that all routines with the same priority gets a chance of running before any data  can change again, so nothing needs to be transferred by value. So no need for threads, thread  pools, endless data copying, Mbytes of stacks etc. - just two or three execution queues.

PS. I will be very busy until next week so I might not be able to continue this thread until then.

 

Answer 13

Renee,

Can you give a fully working  example of the following code:

Private Subroutine Foo()

WebBrowser.Nagivate(“www.foo.com”)

End Sub

Private Sub WebBrowser_NavigationComplete(ByVal sender  AsObject, _
ByVal e As System.NavigationEventArgs) _
Handles WbBrowser.NaVigationComplete

‘Process the data  and continue

End Sub

I have been trying the following but it does not work  (I am using the IExplorer object, not the WebBrowser).

The event  is fired, but it does not give time for the document to be loaded.

The NavigateComplete2 event works even worse, the event is not even fired.

Module Module1

PublicDeclareFunction ShowWindow Lib"user32" (ByVal hwnd AsInteger, ByVal nCmdShow AsInteger) AsInteger

PublicConst SW_SHOWMAXIMIZED AsInteger = 3

PublicWithEvents wb AsNew SHDocVw.InternetExplorer

Dim HTMLDoc As MSHTML.HTMLDocument

Dim iHTMLCol As MSHTML.IHTMLElementCollection

Sub Main()

ShowWindow(wb.HWND(), SW_SHOWMAXIMIZED)

wb.Visible = True

wb.Navigate("https://www.xyz.com")

EndSub

PrivateSub wb_DocumentComplete(ByVal pDisp AsObject, ByRef URL AsObject) Handles wb.DocumentComplete

HTMLDoc = wb.Document

iHTMLCol = HTMLDoc.getElementsByTagName("input")

......

EndSub

EndModule

 

Answer 14

Carsten Kanstrup wrote:

Actually, I have been tempted to post a thread  like this about the abused functions sleep  and CreateGraphichs, but from the opposite point of view!

Unlike many others, I do not regard these functions as bad design. It is correct that Sleep blocks the thread from which it is called, but if it is a background  thread it doesn't matter. If it is the UI thread, things  are not just black and white. By default, the UI thread has higher priority than background threads and thread pool threads, so Sleep may be necessary to allow a job on a low  priority thread to finish. For example, if you want to change a serial port, you need to close the old port and open a new one. However, you must give the system  time to close down the background thread for the old port before creating a new thread for the new port, and the easiest way to do this is to block the high priority UI thread temporary by means of Sleep! In a background thread you can also use Sleep(0) to release the CPU if you cannot utilize the rest of the time slot. Besides, Windoze is so slow that blocking the UI thread for e.g. 200 mS doesn't really matter. If you call  Application.DoEvents() to empty the message  queue before the Sleep command, nobody will notice, and you may save a lot of programming and resources (timers etc.). Besides ReneeC, you are a little wrong. Sleep will not block the process  ability to do anything as you write - just the thread from which it is called. This makes quite a difference.

You mention the changing of a serial port as an example, how long time do you sleep? On my computer it may take 1 second and on my mothers 10 seconds. What is the proper  time? Windows and the .NET framework offers a lot of options to subscribe to various events, why not use those?

Why would you make a background thread sleep? If you need to wait  for a hardware device to close down you should listen for that event  and continue processing when that specific event occurs. If it is not a specific event in the .NET class  you can usually give a callback procedure to be called  when a specific event is raised or API finishes.

Making the UI thread call Sleep is very bad practice. You need to have the message loop  responsive. This is also why you should use background threads/workers to do any heavy work.

Application.DoEvents() is not bad practice but you have to consider the possibility that during the call to Application.DoEvents() your application  got a message to close down and must stop  all processing in a clean way. This is a very common mistake that developers  do when using Application.DoEvents(). You need to check if the application is closing down immediatly after all calls to it.

Thread.Sleep() is not a method you want to use and you should avoid it by all means. Making a thread sleep might have some usage in a device driver where you have to take into consideration for hardware needing to reach a stable state. As example when clicking a mouse button the actual switch in the mouse might bounce on the contact area and give mixed values during a fraction of a second and you can only rely on its value after a few microseconds.

 

Answer 15

Hi Alcedo,

There was a good clue in your last post

pDisp  I'm using a set of C# classes with extended events. I get excellent results. But there are people such as yourself who work  with the COM version and the synchronize in the Navigationcomplete event  by doing something with pdisp.

I think the answer to your question is here.....

Renee

 

Answer 16

Andreas Johansson

Unfortunately, the serial port documentation does not define the necessary time to close down one port before opening a new one. It just says that some time is needed. I don't like it either, but SerialPort has no events, callback methods or anything else, which can tell you when a port is fully closed, so sleep  is the only way I know. If you have a better solution, please let me know, but one thing for sure: As long as the system  is running a high priority UI job it will not get any time to close down a low  priority background  thread, so you need to block the UI thread  temporary to get the job done before a new port is opened from the UI thread.

I fully agree with you and ReneeC that Sleep is not a function you should normally use, but my point is that it may be useful in some situations. The important thing is that you know what you are doing! I also agree with you that there is usually no reason to sleep a background thread, but again my point is that it doesn't matter if you do, so if a programmer kan find sleep useful in a background thread it is not bad programming to use it. In a background thread, Sleep and waiting for a timer  tick does exactly the same thing.

It is correct that if you call  Application.DoEvents(), the system may process  a close down message  (WM_CLOSE), but it is extremely unlikely that you want to close the window simultaneously with selecting a new serial port. Besides, I cannot see how it is possible to make a useful test after Application.DoEvents - what would you test for? When WndProc receives a WM_CLOSE message it will call DestroyWindow(m.hWnd), which closes the window before Application.DoEvents returns, so I guess it is left to the automatic garbage collection or a handler for the form close event  to clean up.

 

Answer 17

Carsten Kanstrup wrote:

Unfortunately, the serial port documentation does not define the necessary time to close down one port before opening a new one. It just says that some time is needed. I don't like it either, but SerialPort has no events, callback methods or anything else, which can tell you when a port is fully closed, so sleep  is the only way I know. If you have a better solution, please let me know,

If you use Thread.Sleep in a background thread  it would be acceptable. I would probably try to approach this by using a timer  (from Threading namespace) and a semaphore.

Create the semaphore, setup the timer to try to open the serial port and wait  for the semaphore to be signalled.

In the timer event  it will try to open the port and if it opens then signal the semaphore, if it fails reschedule the timer and try again until a retry count and then signal the semaphore.

Carsten Kanstrup wrote:

but one thing for sure: As long as the system  is running a high priority UI job it will not get any time to close down a low  priority background  thread, so you need to block the UI thread temporary to get the job done before a new port is opened from the UI thread.

This is not true in windows  and .NET. The scheduler gives all threads some time slice to do work  in. The higher priority thread will get more time that a lower priority thread but it will not block the thread with lower priority.

You should never use Thread.Sleep to block the UI thread, it will make the UI unresponsive and decrease the user  experience. If you need to do heavy work you should try hard to avoid doing it on the UI thread and use threads or asynchronous  calls.

Carsten Kanstrup wrote:

I fully agree with you and ReneeC that Sleep is not a function you should normally use, but my point is that it may be useful in some situations. The important thing is that you know what you are doing! I also agree with you that there is usually no reason to sleep a background thread, but again my point is that it doesn't matter if you do, so if a programmer kan find sleep useful in a background thread it is not bad programming to use it. In a background thread, Sleep and waiting for a timer tick does exactly the same thing.

If you know what you are doing Thread.Sleep can be useful, but it is more of a quick and somewhat dirty way to do arbitrary waiting. I prefer event driven  programming. In your case with serialport reopening Thread.Sleep its not a bad solution as long as its on a background thread.

Carsten Kanstrup wrote:

It is correct that if you call  Application.DoEvents(), the system may process  a close down message  (WM_CLOSE), but it is extremely unlikely that you want to close the window simultaneously with selecting a new serial port. Besides, I cannot see how it is possible to make a useful test after Application.DoEvents - what would you test for? When WndProc receives a WM_CLOSE message it will call DestroyWindow(m.hWnd), which closes the window before Application.DoEvents returns, so I guess it is left to the automatic garbage collection or a handler for the form close event to clean up.

In most cases Application.DoEvents will not be a problem but you should cover that situation. You could handle  the FormClosing event of the form and set a flag that it is closing and check that flag after the call to Application.DoEvents().

Another way to check if a window or control is still valid is to check the IsHandleCreated property  is true.

 

Answer 18

In the case with SerialPort you cannot just try to open the new port. If you do and the old port is not completely closed down, the system  fails!

If you e.g. call:

YourCOMPort.Close()

YourCOMPort.PortName = COMPortsBox.Text

YourCOMPort.Open()

from the UI thread  without any Sleep command between as you often see, there is no way the background  thread gets any time to close down. You will need at least a Sleep(0) statement to release the CPU so that other threads get a chance of running.

It is of course nice that low  priority threads gets some execution  time in case of running high priority threads, but do you have a guarantee that it always gets sufficiant time to close down so that Sleep(0) is enough? What if another low priority thread is also waiting? Will both threads gets some time or only one of the low priority threads?

Sorry, but I still see Sleep as the only solution. However, I completely agree with you that event  driven systems  are the preferred solution. I have used 100% event driven  PLC's for electronic process  control since 1978 and our new fieldbus system Max-i is also event driven.

 

Answer 19

Carsten,

One of the basic  tenets of this thread  has been that use of Threading.Sleep in an event  driven system  is an indication of a design  problem. I think that's really been aptly demonstrated here.

We recognize that serial ports have been around since the Altair which is clue in and of itself. By todays standards, serial ports because of the way they work  are dinosaurs and the presense of serial ports is a design flaw. Wouldn't you say so? 

 

Answer 20

Hi Renee,

I have seen some of the C# classes for Document Complete event  in the help pages. They seem to offer the fine control that is really required.

However, this is VB, not C#

I have done extensive programming with the InternetExplorer object  and control of the document complete by way of the pDisp and other means. However, I always sleep  the thread  while the websites load.

If you could post a simple example of a module in VBE05 for navigating to a website and checking when it is loaded, I would appreciate it and it would probably lead me into the direction you mention.

Many thanks,

Antonio

 

Answer 21

ReneeC

No, the serial port is not dinosaurs or a design  flaw. The only thing that are dinosaurs is the way Microsoft handles  the serial port, which prevents us for utilizing any of the modern communication methods like 9th bit communication with automatic unit addressing and separation of binary telegrams (0-255) by means of break (Microsoft simply throws three vital bits from the UART away). For years, Microsoft has hoped that the serial port would disappear, but today there are even more serial port applications than ever before. Every microprocessor has a serial port and there are numerous GPS applications etc. Profibus, which has a marked share of approximately 51% among fieldbus systems  for electronic process  control, is also using the serial port and our new fieldbus system  Max-i uses serial port for communication between the controller chip and the PC or an embedded microprocessor. The serial port will not disappear for the same reason as the 8051 microprocessor - it is simple!!!

 

Answer 22

Antonio,

It does sound as if you know what you are talking about. I don't have any code  because the problems  you are describing have never occurred for me. I don't have code to support a problem that is not a problem for me. If you don't like c# you can always put  it a dll and forget about it. That's what I've done.

 

Answer 23

Renee,

You started a thread  stating that Threading.Sleep should not be used.

You give an example in Visual Basic that does not work.

I ask you to supply a simple VB code  example to navigate to a website and to confirm when it is fully loaded without sleeping the thread and you are not providing it. Instead you are saying that because you did not have this problem you cannot code it or something like that.

If you are not able to provide a simple working  VB module code for that task without sleeping the thread it is difficult for me to believe that you are right.

However, by all means, prove me that you are.

Thanks,

Antonio

 

Answer 24

I don't have any thing to prove and I am not moved by "proof gambits". You may believe whatever you like. The example was for illustration and I've learned not to pay much attention to "does not work" when there is no further information. "does not work  under what conditions and with what version of the Webbrowser interface and whose version?

You've seen many other experienced  programmers here say do not use Threading.Sleep. Using it is a design  error or is indicative of the presence of a flawed component.

 

Answer 25

Carsten,

I tried to find out some on how the scheduler worked but it seem I was incorrect in that all threads get a time slice to execute in. You were correct, higher prioritized threads will block lower prio threads if the higher prio threads never becomes idle.

With hyperthreading and multiple cores it is more likely all threads get some time but it is not sure. To allow a lower prio thread  to execute I would raise the prio of the thread I need to execute instead of sleeping the current thread. There might be other threads on a higher priority that will block it.

If you need to block the UI thread to execute code  in a background  thread I would say that there is some trouble in the UI code.

For demonstration purpose I have made a new SerialPort class  that uses event  driven approach to reopen the port. When it opens the port (or fails due to retry limit reached) it will raise an event where execution  can be resumed in. Its still in C# and I will translate it to VB also before posting it.

 

Answer 26

Andreas

It is SerialPort, which creates the background  thread, and the SerialPort class  does not have any methods or properties, which makes it possible to identify that thread. How can you raise the prority of a thread  you don't know, and what should you change the priority to when you don't know the priority of all other threads? Besides, raising the priority of the background thread to something higher than the UI thread will block the system  forever, because there is no thread, which can change the priority back!

If sleep  is bad design, changing the priority of a thread, which you don't know anything about, is even worse and a high risk matter!

I am looking forward to see your solution, but note two things:

1) The question is about using the build-in SerialPort class of .NET - not making a completely new class by yourselves.

2) You are not allowed to try to open a new port before the old one is closed down completely - not even in a try statement! The system simply fails if you try to do this.

Don't misunderstand me. I don't like Sleep either (except for what I am going to do now ), but my point is that sometimes it may be the only reasonable solution. Nobody will notice if the UI thread is dead for e.g. 200 mS just after they have given a command to change the port. You cannot give the next command faster. Even if you sleep the thread for 2 sec., nobody will find that unusual.

There are many situations where the UI thread is dead. This is e.g. the case if you transmits in a try statement with e.g. a 2 sec. transmitter timeout and the transmission fails, but nobody will regard this as bad design. It is also the case when you start  your PC. It takes my PC approximately 5 minutes with close to 100% CPU load  before the UI is ready to do anything and approximately 5 minutes to close down, so I miss approximately one working week every year just waiting for the UI thread - probably because true  teaching makes the program  size explode! What is worse - hundreds of waisted cycles or a harmless Sleep(200) statement?

 

Answer 27

No, you were right the first time.  While it is true  that a higher priority thread  always pre-empts a lower priority thread, the scheduler continuously adjusts the actual priority from the programmed priority.  This prevents low  priority threads from getting starved, keeps threads that run  the foreground window responsive and solves nasty priority-inversion problems.

9 out of 10 times, the use of Sleep() in these forums are an attempt to force a procedural programming approach on top of an event-driven architecture.  It is a common mistake, the kind of programming taught in most schools is far removed from the kind of programming you need to keep a non-modal UI such as Windows friendly to the user.  The C++ forums are filled with threads of programmers grappling with the required mental switch.  Cin and cout will be with them for quite a while.

It might be more productive to talk about the legitimate uses of Sleep().  The first one is Sleep(0).  Very useful in a game loop.  It gives you the maximum possible frame rate that still doesn't completely hog the processor, allowing the system  to stay responsive to Alt+Tab and ding-dong for email deliveries (not great examples).  You'll burn 100% CPU time.  The next one is Sleep(1), very useful in soft real-time systems.  Pretty close to the game loop  but keeps the CPU cool.  You'll need this when you have to rely on polling to discover anything happening in the system.  Very common with imperfect drivers, they very often are and can't generate an event.

Nothing after Sleep(1) is useful for a while, at least up to Sleep(45).  You'll just give up the timeslice you got to use the CPU.  If no other thread requires service, the CPU stops and doesn't wake  up again until the next clock tick or hardware interrupt.  The next clock tick interrupt happens up to 15 msec after you relinguished the CPU.  The scheduler computes new adjusted priorities and might run another thread because of it.  A hardware interrupt invariably releases a thread that was waiting for an I/O operation to complete (read from disk or network interface card, etc).

Beyond that, Sleep() is only useful to solve a "don't know enough about the state  of the object" problem.  The examples that were given in this thread are real.  The SerialPort class  indeed has a nasty problem where you can't open a port too quickly after closing it.  There's a background  thread that starts an overlapped I/O request to fire the DataReceived event.  That thread needs to exit before you can successfully open the port again.  This is a flaw in the class design.  Sleep() can solve it but the solution is not perfect.  The exact amount of sleep  you need to be sure the thread exits is dependent on system load.  In other words, the amount of time needed  before the background thread gets scheduled again to detect that it should exit.  Sleep(500) is probably as low as you can safely go.  Not closing and re-opening the port is of course the better solution.

The example with WebBrowser is real too.  Relying on DocumentCompleted has a common mistake, the programmer doesn't realize that it gets fired more than once when the web page contains frames.  However, time is needed after the last DocumentCompleted event  until the scripting engine become functional.  Presumably because the JavaScript or VBScript runtime needs to be loaded and execute the DOM events.  There is no public  event that you could use that says the scripting engine is done executing.  All you can do is Sleep() for a while, I doubt anybody would commit to a number.
 

Answer 28

Carsten Kanstrup wrote:

It is SerialPort, which creates the background  thread, and the SerialPort class  does not have any methods or properties, which makes it possible to identify that thread. How can you raise the prority of a thread  you don't know, and what should you change the priority to when you don't know the priority of all other threads? Besides, raising the priority of the background thread to something higher than the UI thread will block the system  forever, because there is no thread, which can change the priority back!

My comment about changing the threads priority is not what I suggest for the SerialPort class or any other thread you do not have control of. If you have control of the thread, its your code  and you can make it change back  priority.

Carsten Kanstrup wrote:

If sleep  is bad design, changing the priority of a thread, which you don't know anything about, is even worse and a high risk matter!

I was not explicit about it but it was not my intention to suggest you change priority of any other thread than your own, where you own the code and can determine any implications of making it run  at a higher priority.

Carsten Kanstrup wrote:

1) The question is about using the build-in SerialPort class of .NET - not making a completely new class by yourselves.

2) You are not allowed to try to open a new port before the old one is closed down completely - not even in a try statement! The system simply fails if you try to do this.

The whole point of my demonstration is to show that you do not need to use Thread.Sleep() on the UI thread when reopening the SerialPort. It is not about being able to detect that it can be re-opened so your suggestion for requirement do not apply to my demonstration. I do use the SerialPort class.

Carsten Kanstrup wrote:

Don't misunderstand me. I don't like Sleep either (except for what I am going to do now ), but my point is that sometimes it may be the only reasonable solution. Nobody will notice if the UI thread is dead for e.g. 200 mS just after they have given a command to change the port. You cannot give the next command faster. Even if you sleep the thread for 2 sec., nobody will find that unusual.

Sometimes Thread.Sleep is usable however usually not in a UI thread, nobugz list a few examples like Thread.Sleep(0). For most other values for sleep I would say the code better belongs in its own non-UI thread.

Using sleep on UI threads may decrease performance of other applications. Here is an example (a bit stupid but not completly unreal that it may happen in some way or another). I have an application  that reads the title of every open form on my desktop. It manages to do this in less 50ms and I schedule it to scan every 100ms. Every time this scanning application ask your UI what the title is of the form it might have to wait  up to 200ms (or 2000ms if you think nobody will notice that) before getting an answer decreasing the performance drastically of this scanning application.

Carsten Kanstrup wrote:

There are many situations where the UI thread is dead. This is e.g. the case if you transmits in a try statement with e.g. a 2 sec. transmitter timeout and the transmission fails, but nobody will regard this as bad design.

Dead UI thread (stopped responding) is not giving a rich and good user  experience and should be avoided. Don't do synchronous IO on the UI thread, use asynchronous  IO or background thread. In SerialPorts case you probably need to use a background thread and events  to signals its completion.

Carsten Kanstrup wrote:

It is also the case when you start  your PC. It takes my PC approximately 5 minutes with close to 100% CPU load  before the UI is ready to do anything and approximately 5 minutes to close down, so I miss approximately one working week every year just waiting for the UI thread - probably because true  teaching makes the program  size explode! What is worse - hundreds of waisted cycles or a harmless Sleep(200) statement?

When you boot your PC there are many processes starting  up and loading data  from the harddrive. This may result in all threads not getting much or any time to run. This is not a UI thread design  issue, its your computer not having enough resources to deal  with the load. Solution is to get better and faster hardware and try to load less application on computer start.

Thread.Sleep has its uses (see nobugz informative post) but very few of those are to be used in the UI thread.

 

Answer 29

Andreas

In the example with your scanning application  you are far out - sorry to say it. I talk about a 200 mS delay when you change the serial port and you may never do that or only a few times a day. I am not talking about an infinite loop  with a Sleep(2000) statement. The case with the serial port is actually one of these, which nobugz mentioned, where it may be appropriate to use Sleep(). Besides, I regard a scanning routine as very bad design. P.t. I am running some design  software (Libero) from Actel for their field programmable gate arrays (FPGA), and every sec. they scan for changes in the files. The result is that on big projects like mine, they use up to 33% of the CPU time for doing absolutely nothing with the result that everything is slowed down to snail speed. This is what I call  really bad design!

It is correct that sleeping the UI thread  does not give a good user  experience, but this is also the case with the insane time to start  and close the computer, which drives me crazy. I could have one more week off and still be equal productive if it was not for this. Unfortunately, the solution with better and faster hardware is the only way many Windows and Microsoft programmers see. They simply don't have the word "efficiency" in their vocabulary. With Vista they have even pushed the absolute state  of the art computer to the limit, so they won't be able to fight back  when Apple releases the new version of their OS. It is thought-provoking that the enormous power consumption in the IT world coursed by the never ending demand for faster computers is responsible for a CO2 emission as big as the entier air transport! We cannot flee to another planet when we have destroyed this one, so it is my hope  that in a not too far future, Microsoft and others will learn to do things  in a less resource demanding way!

PS. How do you get these quotations "Carsten Kanstrup wrote"? With the new verion of this forum, I can no longer even copy some text to comment it.

 

Answer 30

Carsten Kanstrup wrote:

In the example with your scanning application  you are far out - sorry to say it. I talk about a 200 mS delay when you change the serial port and you may never do that or only a few times a day. I am not talking about an infinite loop  with a Sleep(2000) statement. The case with the serial port is actually one of these, which nobugz mentioned, where it may be appropriate to use Sleep(). Besides, I regard a scanning routine as very bad design. P.t. I am running some design  software (Libero) from Actel for their field programmable gate arrays (FPGA), and every sec. they scan for changes in the files. The result is that on big projects like mine, they use up to 33% of the CPU time for doing absolutely nothing with the result that everything is slowed down to snail speed. This is what I call  really bad design!

I only used the scanning example to prove the point that blocking an UI thread with sleep  or any other way do not only affect the application you do it in but could also have an effect on other windows  applications and windows itself. Lets say that I have an application that reports unresponsive applications (1 second without responding) and then kills them. If you are blocking the UI thread  for 2 seconds to do a serialport write (2000ms timeout that fails) it would look like unresponsive to this monitoring application and get shutdown.

In my example with reopening the serial port I use a timer  but since the timer event  is raised in another thread it might just as well been a new backgroundthread that retries to open the tread and on completion  raises the event. They both basically work  the same. Will post it later today, though it may not be tested that well. I have no equipment to connect to the port!

As long as you don't make the UI thread sleep (at all, except Thread.Sleep(0) which should be equivalent to Application.DoEvents()) I agree there are valid uses for it in non-UI threads, SerialPort reopening being one. The issue  is rather that Thread.Sleep is not used correctly and that is why this thread was started and why I joined in the discussion. Maybe its better to join nobugz in listing and explaining the situations where it can be useful. I have none to add to that list at the moment.

The boot time and power cosumption of todays computer are better not discussed here and rather elsewhere like in hot technology or show & tell.

Carsten Kanstrup wrote:

PS. How do you get these quotations "Carsten Kanstrup wrote"? With the new verion of this forum, I can no longer even copy some text to comment it.

Hit quote instead of reply to get a new message  will all the next quoted. I then add the [ /quote] tag before I enter my comment and add [ quote user="user"] to continue the quote. You'll see the tags if you just hit the quote button.

I also saw its not possible to copy text from the previous message when replying. Not sure whats up with that.

 

Answer 31

Sorry, but Sleep(0) is not equivalent to Application.DoEvents(). Application.DoEvents() will empty the entire message  queue, but Sleep(0) only releases the CPU (time slot) and reinsert the thread  at the back  of the active queue. If Sleep() is called  from the UI thread, not a single further message has been processed  when it returns.

You might be able to open SerialPort from another thread than the UI thread, but if this thread does not have a message pump, it is a terrible job to synchronize the two threads when you e.g. wants to change the settings or open and close the port, so it is not worth the effords just to replace a harmless Sleep(200) statement, which nobody will notice. If you are in doubt, just download MaxiCOM from our knowledgebase http://www.innovatic.dk/knowledg/SerialCOM/SerialCOM.htm and try to change the port from the ComboBox. There is absolutely no delay to notice so it has no meaning to talk about a bad user  experience. The only thing, which may irritate you, is the time it takes to fire up the .NET runtime and load  and compile the program  (Windows XP), but of course that dead time is not regarded as bad programming or bad user experience!

 

Answer 32

Yay, my mistake. I saw some example code  and misunderstood what it demonstrated. Disregard that comment that Sleep(0) would be equivalent as DoEvents(). Its only good to let other threads with higher/same prio run.

Here is the code to reopen the port in a new thread  using a timer  and an event  to signal completion.

SerialPortEx.VB

Code Snippet

Imports System.IO

Imports System.IO.Ports

Imports System.Threading

'''

''' Reopen the serial port using the same settings

'''

PublicClass SerialPortEx

  Inherits SerialPort

  '''

  ''' Reopen the serial port using the same settings

  '''

  PublicSub ReOpen()

    Dim isReOpening AsInteger = Interlocked.CompareExchange(_isReOpening, 1, 0)

    If 0 = isReOpening Then

      IfTrue = IsOpen Then

        Close()

      EndIf

      _currentRetryCount = 0

      _reOpenTimer = New Timer(New TimerCallback(AddressOf _reOpenTimerCallBack), Me, _dueTime, Timeout.Infinite)

    EndIf

  EndSub

  '''

  ''' Timer callback to try to retry the serialport object.

  '''

  ''' The SerialPortEx object  to try to reopen connection for

  PrivateSub _reOpenTimerCallBack(ByVal state  AsObject)

    Dim serialPortEx As SerialPortEx = CType(state, SerialPortEx)

_currentRetryCount = _currentRetryCount + 1

    Dim raiseCompletedEvent AsBoolean = False

    Dim reason As ReOpenCompletedReason = ReOpenCompletedReason.Unknown

    Try

serialPortEx.Open()

    Catch ex1 As InvalidOperationException

    Catch ex2 As IOException

    EndTry

    IfTrue = serialPortEx.IsOpen Then

reason = ReOpenCompletedReason.Opened

raiseCompletedEvent = True

    ElseIf _retryCount = _currentRetryCount Then

reason = ReOpenCompletedReason.RetryLimitReached

raiseCompletedEvent = True

    Else

' Reschedule timer

      IfFalse = _reOpenTimer.Change(_dueTime, Timeout.Infinite) Then

reason = ReOpenCompletedReason.InvalidTimer

raiseCompletedEvent = True

      EndIf

    EndIf

' Done, raise event with reason why

    IfTrue = raiseCompletedEvent Then

OnReOpenCompleted(New ReOpenCompletedEventArgs(reason))

    EndIf

  EndSub

'''

''' Raises the OnDocumentCompleted event

'''

''' ReOpenCompleted events  args containing the reason

  ProtectedOverridableSub OnReOpenCompleted(ByVal e As ReOpenCompletedEventArgs)

_reOpenTimer.Dispose()

_reOpenTimer = Nothing

    Dim isReOpening AsInteger = Interlocked.CompareExchange(_isReOpening, 0, 1)

    RaiseEvent ReOpenCompleted(Me, e)

  EndSub

''' 0 if not currently trying to reopen, otherwise 1 when trying to reopen port

  Private _isReOpening AsInteger = 0

''' Limit of retries

  Private _retryCount AsInteger = 5

''' Current count of retries

  Private _currentRetryCount AsInteger = 0

''' Time before first and each consecurity attempt to reopen port

  Private _dueTime AsInteger = 100

''' Timer used to try to connect

  Private _reOpenTimer As Timer

''' ReOpenCompleted event

  PublicEvent ReOpenCompleted As ReOpenCompletedEventHandler

EndClass

'''

''' Reasons that reopening ended ok or failed

'''

PublicEnum ReOpenCompletedReason AsInteger

Unknown

Opened

RetryLimitReached

InvalidTimer

EndEnum

'''

''' Event arguments for reopencompleted event.

'''

PublicClass ReOpenCompletedEventArgs

  Inherits EventArgs

'''

''' Constructor

'''

''' Reason for completing reopening

  SubNew(ByVal reason As ReOpenCompletedReason)

_reOpenCompletedReason = reason

  EndSub

'''

''' Get the reason

'''

  PublicReadOnlyProperty Reason() As ReOpenCompletedReason

    Get

      Return _reOpenCompletedReason

    EndGet

  EndProperty

'''

''' Reopening completed reason

'''

  Private _reOpenCompletedReason As ReOpenCompletedReason

EndClass

'''

''' Event handler for reopencompleted event

'''

''' Sender of event

''' Event args

PublicDelegateSub ReOpenCompletedEventHandler(ByVal sender  AsObject, ByVal e As ReOpenCompletedEventArgs)

Handle the event like this and sample how to call  it...

Code Snippet

SerialPortEx1.Open()

SerialPortEx1.ReOpen()

PrivateSub SerialPortEx1_ReOpenCompleted(ByVal sender As System.Object, ByVal e As SerialPortReOpenSampleVB.ReOpenCompletedEventArgs) Handles SerialPortEx1.ReOpenCompleted

  MessageBox.Show(e.Reason.ToString())

EndSub

 

Answer 33

Holy Cow . That's what I call  a replacement for one or two harmless statements, but the question is - will it give a better user  experience to justify this extreme increase in complexity?

Nobugz may be right that you need a Sleep(500) statement to be resonable safe, but on my fairly old computer, I have never seen any problems  with Sleep(200) - not even with Sleep(100). Since your solution does not block the high priority UI thread  where most time consuming jobs like graphics etc. are done, you need a considerably longer time to reopen the port than I do - maybe 2 seconds - nobody knows - it is extremely unpredictable. If you use Application.DoEvents() before the Sleep(200) statement as I do, nobody will notice that the UI thread is dead for 200 mS after they have selected the new port, but in your case, you need to block e.g. the transmit command until the new port is reopened, so your solution is not even finished yet and the user may discover this delay!

Sorry, I still see Sleep as the only resonable solution - and the one, which gives the best user experience, which this is all about!

 

Answer 34

Carsten Kanstrup wrote:

Holy Cow . That's what I call  a replacement for one or two harmless statements, but the question is - will it give a better user  experience to justify this extreme increase in complexity?

To do things  properly may require a bit more work  than just using a couple of statement. This is not extreme increase of complexity. A developer  that uses SerialPortEx will not see any of the class  code. Just have to call ReOpen and handle  ReOpenCompleted event. Quite standard harmless .NET development if you ask me.

Carsten Kanstrup wrote:

Since your solution does not block the high priority UI thread  where most time consuming jobs like graphics etc. are done, you need a considerably longer time to reopen the port than I do - maybe 2 seconds - nobody knows - it is extremely unpredictable.

Thats the whole point with my solution and this thread, to not block the UI thread with waiting for something to happen!

The port is attempted to reopen after 100ms in a new thread, the UI thread will not block. The code runs  very predictable.

Carsten Kanstrup wrote:

If you use Application.DoEvents() before the Sleep(200) statement as I do, nobody will notice that the UI thread is dead for 200 mS after they have selected the new port, but in your case, you need to block e.g. the transmit command until the new port is reopened, so your solution is not even finished yet and the user may discover this delay!

Incorrect, you handle the ReOpenCompleted event  and start  the transmitting on successful reconnect. This is event driven  development, act on events  instead of blocking, synchronous calls.

My solution is an demonstration that you do not have to use sleep  to create the delay to reopen ther serialport. The sample code  will not cause ANY delays at all on the UI thread other than code running. It is quite easy to build on this demonstration code to create a fully event driven serialport class.

Carsten Kanstrup wrote:

Sorry, I still see Sleep as the only resonable solution - and the one, which gives the best user experience, which this is all about!

I general I still disagree with you and I have demonstrated a working  event driven approach. If you feel your solution works ok and customers are happy I also see no reason to change your solution. This thread is about educating users  that in general Thread.Sleep() is not the solution, with a few situations where it actually is usable, nobugz listed most of those.

I will not back  down with regards to the UI thread, do not use Thread.Sleep() in it.

 

Answer 35

Sorry, but your code  will not work  in a reliable way. 100 mS is simply not enough - especially not in your case!

In ReOpen() you close the port and starts a 100 mS timer, and when this timer runs  out, the_reOpenTimerCallBack method reopens the port in a try statement. However, if the old port has not closed down yet the system  simply fails, as I have told you before e.g. in my two demands (I thought  that this was what you were going to do, so I warned you). If a try statement was enough to solve the problem, a small try loop  with Application.DoEvents() on the UI thread  could have solved the problem nicely, but it is not that easy. You simply get a fatal failure if you in any way try to reopen the port too early! Because you don't block the UI thread, there may be many time-consuming, high-priority jobs waiting, which will be executed before the background  thread gets a chance of shutting down. So not only is the time you need much longer than if you use Sleep, but the necessary time is completely unpredictable. You will never be able to make a resonable reliable program  unless you set the timer  to e.g. 5 seconds or something like that. This will surely not give a good user  experience, and fatal errors will not do that either!

 

Answer 36

There is nothing stating that a timer  event runs  at any lower priority than the UI thread. As long as the UI thread  finishes and returns to idle state  it will let other threads run. If your background  threads get delayed it is most likely because some other issue  in your design/code.

Using a loop  with DoEvents() call  on the UI thread is about the same as using a Timer but much more bad! If you do not have a Thread.Sleep() in the loop you will use about 100% cpu resources. If you have a Thread.Sleep() you will block the UI thread. Bad!

I told you from the very start  that I have not considered your demands, my demonstration is purely to show that it is possible in a reliable way to have an event  driven approach to reopening the serialport. Non-blocking and non-looping approach.

I use try catch to handle  the situations where the port can not be opened. There is nothing fatal about this error. If the reopening fails with an exception I should probably have included it in the ReOpenCompletedEventArgs so the developer  also have access to it.

If you further want to discuss this SerialPort reopening issue I will soon post an article here describing my event driven approach where we can continue that. Otherwise I suggest we keep to the topic here. Why not to use Thread.Sleep and its exception where it may be usable. I know you have your view and I have mine but we are only re-iterating it over and over again. You are also welcome to discuss via e-mail if you like, its in my profile.

 

Answer 37

Sorry, but I can't find your e-mail address on your home page. It is possible to send  a message  to you, but it redirects me to some unknown site, which requires JavaScript to be enabled. I usually run  with my browser safety set to high and only reduces the safety for sites I really thrust like yours, but not for unknown ones or any redirection to unknown places. What is wrong with a good old e-mail address? Mine is mail @ innovatic . dk. I agree with you that it is probably better to continue this by e-mail, but since I couldn't find your address, you will get my last comment here. Besides, this thread  has already got 813 views and the number is raising fast so many must find this discussion  (a good fight) interesting and I am sure that ReneeC also finds it better than just digging the thread down in the archive. I presume this is why she asked me to participate !

I know that the timer event  does not have lower priority than the UI thread. What happens is probably (I am not quite sure) that the callback method gets posted as an APC software interrupt (IRQL 1) to the APC queue of the thread  when the timer runs  out (IRQL 30), so that when the thread starts running, the callback method will be executed immediately  (thread interrupted). However, this makes no difference or just makes things  worse since you don't get any extra delay.

The problem is that you cannot know when the UI thread finishes and returns to idle state. If you start  a very big job, which runs on the UI thread, and then switch the window to change the COM port, the message queue may contain numerous messages  enough to keep the CPU load  close to 100% for a while! If a high priority thread entierly blocks for low  priority threads, your code  would simply fail under those circumstances, but we know from nobugz that this is not the case. Low priority threads still get some time, but the question is how much in cases like this where the CPU load is close to 100%. When you sleep  the UI thread you get rid of the most time consuming jobs and the scheduler has only jobs left, which is unlikely to have higher priority than the background  thread of SerialPort, which uses standard priority. Therefore, it is just a matter of a number of time slices before the background thread runs and can close down. This time is much more predictable than if high-priority, time-consuming jobs are also allowed to run.

Application.DoEvents() is in no way the same as a timer  and it does not increase the CPU load to 100%. It just executes the messages on the message queue one by one. The messages on the message queue are going to be executed anyway so it makes absolutely no difference if they are executed immediately (Application.DoEvents) or when the present message has finished its own execution  and returns. Of course a loop  with Application.DoEvents will increase the CPU load if the message queue is empty, but if it was possible to solve the problem with a try statement (it isn't), the CPU load would only be increased until the port has closed down and ready to reopen.

Of course using try-catch is not fatal, but it gets fatal if you try to do it too early, and in your case there is absolutely no way you can predict the necessary time before you try - that's my point!

My final conclusion:

Application.DoEvents()

Sleep(200)  ' or 500 in case of high reliability applications

is the only resonable way to solve the SerialPort reopen problem, and the one, which gives the highest performance and best user  experience!

 

Answer 38

Yes, I asked you to join us, Carsten because personally I like and sometimes we agree, howevr when we disagree we do it amicably.

It does seem to  me that Andreas had a point where he said it didn't seem like you were really hearing what he was

saying to you and that you are going round and round. That tends to happen when one doesn't acknowedge what's being and people worry about "winning conversations". When that happens, it seems to me that everyone loses.
 

Answer 39

ReneeC,

I saw this when i was doing some searching on fixing my unbound recursion problem and i wanted to get your thoughts on it since it relates to thread  sleeping.

http://msdn2.microsoft.com/en-us/library/ywkkz4s1(VS.80).aspx

This is what it says at the end  of the page.

You must allow the background  worker thread to sleep  for a few milliseconds, or else your program  will freeze until the worker thread is complete. Add this line to the Do Loop in the CountWords subroutine  of the Words class.

System.Threading.Thread.Sleep(10)
I was kind of curious about this because i am trying to understand timers  and background workers.
I have been using timers to do work  in the background for me lately instead of trying to use a background worker or using application.dovents.
Thanks
P.S. i haven't read all the posts but i do like seeing the responses from all points.
A good debate helps us newbies understand better.  Atleast me anyway.  And i wanted to say that i understand your point of view on why not to use it when there are better ways to handle  "sleeping".
 

Answer 40

Hi Jso6.

I'm just ready to climb on  jet. I will be flying until 9:00 am tomorrow and then I will leave soon after than on vacation. I'd love to discuss this. But it's going to be much later.

I will stand by what I said.

 

Answer 41

I think it's totally acceptable to call  Threading.Thread.Sleep in a background  tread hence its inclusion in the Threading library. On the other hand blocking the UI and associated message  loop in the UI tread is bad.


As for the web browser example the code  is just plain bad under 2.0+ of the framework. A better solution to see if a document is finished loading is to check ReadyState property  of the WebBrowser control in the DocumentComplete.event. This is because the Document complete event  can be fired multiple times when loading a web page. No sleep  required ;-)


An example DocumentComplere handler using this tequnique might look like this:

Code Snippet

Private Sub WebBrowser1_DocumentCompleted(ByVal sender  As Object, _

                                          ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) _

Handles WebBrowser1.DocumentCompleted

Dim browser As WebBrowser = CType(sender, WebBrowser)


If browser.ReadyState <> WebBrowserReadyState.Complete Then

ExitSub

EndIf


'Process Page Here

Me.Text = String.Format("Loaded {0}", browser.DocumentTitle)

EndSub



I should also point out I've seen a lot of confusion (mostly from us VB6 hacks) between Threading.Thread.Sleep and Application.DoEvents. The former blocks the current thread  the later does quite the oppisite.

 

Answer 42

ReneeC

... or maybe Andreas does not listen to me?

It is common sense that if you are in a queue with 100 people to get an aeroplane ticket to an aeroplane with only one seat and some of them even have VIP cards, the time it takes before you can fly is both longer and much more unpredictable that if there are only 10 persons with the same rights. So in the first case you need a bigger safety margin to ensure that you reach your destination in time.

I know that Andreas is a much more experienced  VB programmer than I am and I respect that, but this has nothing to do with programming - it's just common sense, and I am not the kind of guy, which just bend in the dust when I see the signature: Moderator MVP.

Nobugz has mentioned four situations where it is acceptable to sleep  the UI-thread:

1) Sleep(0) to release the CPU.

2) Sleep(1) which does the same, but keeps the CPU cool in case of a infinite loop  or a poll loop.

3) To solve the SerialPort reopen problem, which is coursed by a flaw in the SerialPort class.

4) To solve the WebBrowser problem when the page is build with frames.

I find his answer excellent and the best one in this thread! It clearly tells what this is all about. Don't sleep the UI-thread except for those four situations, where there is no other resonable solution. Why can't you and Andreas accept number 3 (or 4, which I know nothing about)? Fanaticism is one of the worst things  in this world and I find statements like "Never, ever sleep the UI-thread" quite fanatic!

 

Answer 43

js06 wrote:

I saw this when i was doing some searching on fixing my unbound recursion problem and i wanted to get your thoughts on it since it relates to thread  sleeping.

http://msdn2.microsoft.com/en-us/library/ywkkz4s1(VS.80).aspx

This is what it says at the end  of the page.

You must allow the background  worker thread to sleep  for a few milliseconds, or else your program  will freeze until the worker thread is complete. Add this line to the Do Loop in the CountWords subroutine  of the Words class.

System.Threading.Thread.Sleep(10)

I checked out this sample and directly suspected that the reason the user  comment says to do Thread.Sleep(10) is not the proper  solution. Why slow down the application? If you scan a textfile with 10000 lines it will just sleep for 100 seconds.

The issue  is that the backgroundworker invokes ReportProgress on every line it counts. That will flood the UI thread with calls to update it. The proper solution is to limit how often the background worker updates the UI.

Replace this

Code Snippet

worker.ReportProgress(0, state)

with this

Code Snippet

If LinesCounted Mod 100 = 0 Then

  worker.ReportProgress(0, state)

EndIf

It will only call  ReportProgress on every 100 lines counted. This fix keeps the UI responsive for me. No reason to use Thread.Sleep().
 

Answer 44

"To solve the WebBrowser problem when the page is build with frames."

1.) I'm writing to you at this moment and have been for the last eighteen months on a tabbed web browser of my own design  that has absolutely no difficulty  with frames and also no Threading.Sleep calls in any of the 10,000 lines of code.

Sleep(0) - Earlier, I said very clearly that there is no problem with sleep  (0). But's that's not really a sleep, is it?

And, as far as using sleep to keep the cpu cool, that's an illusion because of multi-tasking. The machine will process  other items while our poorly designed process sleeps away. It may protect a cpu locally where locally really means this process, but certainly not globally.

Here is a line of code  that in releases the cpu in an event  driven system:

return

Polling loops run  awry? Whatever happened to good design?

 

Answer 45

Some notes to what has been posted here so-far:

- No need for Sleep() when you open another serial port, just create a new SerialPort instance
- Sleep() is needed  in WebBrowser only when you need to wait  for Javascript or VBScript event  handlers to finish executing
- Sleep(0) will cause a sleep  when there is another higher priority thread  ready to run
- Sleep(1) will keep the CPU cool, the implicit assumption is that it is your process  that is burning cycles and every other process is operating  normally
- The problem with Control.Invoke() is real, Sleep() is a very poor (but effective) fix.  Counting loops isn't a very good fix either, you'll want to measure time.  Check this thread for the pattern
- Main loops that call  Sleep() are common in game and industrial automation programming.  That has more to do with imperfect hardware that can't generate I/O completion events  than poor design.
 

Answer 46

This is the high caliber type of thread  that really enriches this forum.

Thank you for all.

I have asked for a code  example of a module in VBE2005 for checking when a page has been done loading without sleeping the thread and I have not seen it yet.

Renee, I am not trying to throw a gambit, I am trying to settle this issue  and enhance my knowledge.

Again, I have been trying to program  this extensively for some time.

Here is my code (please note it allows for pages with frames):

Module Module1

PublicWithEvents wb AsNew SHDocVw.InternetExplorer

Public dnc AsBoolean = True

Sub Main()

wb.Visible = True

wb.Navigate("http://www.ft.com/home/uk/")

While wb.Busy Or dnc

System.Threading.Thread.Sleep(100)

EndWhile

EndSub

PrivateSub wb_DocumentComplete(ByVal pDisp AsObject, ByRef URL AsObject) Handles wb.DocumentComplete

If pDisp Is wb.Parent Then

Beep()

dnc = False

EndIf

EndSub

EndModule

Can someone please give me a module example that does the same without sleeping the thread? I think it is not possible, because the main process  is not kept open for the events  to be fired.

(With a windows  form it is different. It is straightforward for a simple navigation without re-navigation from the same page. This is the code that uses the WebBrowser and the .COM IE object)

PublicClass Form1

PublicWithEvents wb AsNew SHDocVw.InternetExplorer

PrivateSub Button1_Click(ByVal sender  As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

WebBrowser1.Navigate("http://www.ft.com/home/uk/")

EndSub

PrivateSub WebBrowser1_DocumentCompleted(ByVal sender AsObject, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted

If e.Url.ToString = WebBrowser1.Url.ToString Then Beep()

EndSub

PrivateSub wb_DocumentComplete(ByVal pDisp AsObject, ByRef URL AsObject) Handles wb.DocumentComplete

If pDisp Is wb.Parent Then Beep()

EndSub

PrivateSub Form1_Load(ByVal sender AsObject, ByVal e As System.EventArgs) HandlesMe.Load

wb.Visible = True

wb.Navigate("http://www.ft.com/home/uk/")

EndSub

EndClass

Please note that being required to write processing code in DocumentComplete event  is very limiting because it quicky runs  into looping problems.

Thanks,

Antonio

 

Answer 47

nobugz wrote:
Some notes to what has been posted here so-far:
- The problem with Control.Invoke() is real, Sleep() is a very poor (but effective) fix.  Counting loops isn't a very good fix either, you'll want to measure time.  Check this thread for the pattern

To fix my solution with this in regard.

Add a declaration for a timer  to use to measure update intervals.

Code Snippet
Dim lastreport As DateTime = DateTime.Now

Replace this line in CountWords method

Code Snippet
worker.ReportProgress(0, state)

with this

Code Snippet
If (DateTime.Now - lastreport).Milliseconds > 10 Then
   worker.ReportProgress(0, state)
   lastreport = DateTime.Now
End If

This will limit that ReportProgress() is only called  roughly every 10 milliseconds.

 

Answer 48

Check this thread for code  that detects completion  on a multi-frame web page.
 

Answer 49

asalcedo wrote:

Module Module1

PublicWithEvents wb AsNew SHDocVw.InternetExplorer

Public dnc AsBoolean = True

Sub Main()

wb.Visible = True

wb.Navigate("http://www.ft.com/home/uk/")

While wb.Busy Or dnc

System.Threading.Thread.Sleep(100)

EndWhile

EndSub

PrivateSub wb_DocumentComplete(ByVal pDisp AsObject, ByRef URL AsObject) Handles wb.DocumentComplete

If pDisp Is wb.Parent Then

Beep()

dnc = False

EndIf

EndSub

EndModule

Can someone please give me a module example that does the same without sleeping the thread? I think it is not possible, because the main process  is not kept open for the events  to be fired.

windows  form starts a message  loop with Application.Run(new Form1()). If it does not do that it exits when the end  of the starting  method is reached. Use Application.Exit() to stop  the message loop  and exit the application.

Note that when you start  a message loop your main thread  becomes event  driven. That is why I placed the Exit() in the DocumentCompleted() event.

You should be able to do something like this.

Code Snippet

Sub Main()

   wb.Visible = True

wb.Navigate("http://www.ft.com/home/uk/")

Application.Run()

EndSub

PrivateSub wb_DocumentComplete(ByVal pDisp AsObject, ByRef URL AsObject) Handles wb.DocumentComplete

If pDisp Is wb.Parent Or wb.Busy = False Then

Beep()

Application.Exit()

EndIf

EndSub

 

Answer 50

I just checked that page and my browser displayed it identically with IE7.

There is no completion  checking in my Navigation Competion routine so I reasoned that it has to occur in the C# extended events  control that I'm using.

Here it is:

using System;

using System.Collections.Generic;

using System.Text;

using System.ComponentModel;

namespace ExtendedWebBrowser2

{

///<summary>

/// Used in the new navigation events

///</summary>

publicclassBrowserExtendedNavigatingEventArgs : CancelEventArgs

{

privateUri _Url;

///<summary>

/// The URL to navigate to

///</summary>

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]

publicUri Url

{

get { return _Url; }

}

privatestring _Frame;

///<summary>

/// The name of the frame to navigate to

///</summary>

[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]

publicstring Frame

{

get { return _Frame; }

}

privateUrlContext navigationContext;

///<summary>

/// The flags when opening a new window

///</summary>

///

publicUrlContext NavigationContext

{

get { returnthis.navigationContext; }

}

privateobject _pDisp;

///<summary>

/// The pointer to ppDisp

///</summary>

publicobject AutomationObject

{

get { returnthis._pDisp; }

set { this._pDisp = value; }

}

///<summary>

/// Creates a new instance of WebBrowserExtendedNavigatingEventArgs

///</summary>

///<param name="automation">Pointer to the automation object  of the browser</param>

///<param name="url">The URL to go to</param>

///<param name="frame">The name of the frame</param>

///<param name="navigationContext">The new window flags</param>

public BrowserExtendedNavigatingEventArgs(object automation, Uri url, string frame, UrlContext navigationContext)

: base()

{

_Url = url;

_Frame = frame;

this.navigationContext = navigationContext;

this._pDisp = automation;

}

}

}

 

Answer 51

Andreas Johansson wrote:

You should be able to do something like this.

Code Snippet

Sub Main()

   wb.Visible = True

wb.Navigate("http://www.ft.com/home/uk/")

Application.Run()

EndSub

PrivateSub wb_DocumentComplete(ByVal pDisp AsObject, ByRef URL AsObject) Handles wb.DocumentComplete

If pDisp Is wb.Parent Or wb.Busy = False Then

Beep()

Application.Exit()

EndIf

EndSub

Andreas,

But I do not want to exit the application.

I want to process  the wb.document, then click on a link in the same document and process again etc.

How can you do that without sleeping?

Thanks,

Antonio

 

Answer 52

Did you read nobugz post?

 

Answer 53

Yes, I read nobugz post.

It is very simplistic, does not work  in many cases (when frame.count does not give the right answer or when there are frames within frames, of example) and does not answer the question of re-navigating without sleeping.

So far I have not learned anything new on this issue. I have posted long ago my solutions about this that include the proper  (manual) counting of the frames and the code  I posted earlier.

 

Answer 54

asalcedo wrote:

But I do not want to exit the application.

I want to process  the wb.document, then click on a link in the same document and process again etc.

Instead of calling  Application.Exit() you can call  what ever method you want to process the loaded document or what you want to do. However once you are finished with the processing you need you must call Application.Exit() to exit the application. If you do not call it the application  will not close until you close it with task manager or similar.

 

Answer 55

I don't think you've made the best choice in selecting webbrowser objects. I use a C# set that's readily available here in a dll. It exposes the extended events  and I never have to mess with navigation at all. I have no special navigation completion code  at all and it works fine.

See http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1264835&SiteID=1

 

Answer 56

Andreas,

Ok, let us concentrate our minds in a specific example and let us go step by step.

The following code  does not work  it does beep correctly but the HTMLDoc is not evaluated

Imports System.Windows.Forms

Module Module1

PublicWithEvents wb AsNew SHDocVw.InternetExplorer

Public HTMLDoc As MSHTML.IHTMLDocument2

Public iHTMLCol, ihtmlcolb As MSHTML.IHTMLElementCollection

Public iHTMLEle As MSHTML.IHTMLElement

Sub Main()

wb.Visible = True

wb.Navigate("https://www.inversis.com/")

Application.Run()

EndSub

PrivateSub wb_DocumentComplete(ByVal pDisp AsObject, ByRef URL AsObject) Handles wb.DocumentComplete

If pDisp Is wb.Parent And wb.Busy = FalseThen

Beep()

HTMLDoc = wb.Document

iHTMLCol = HTMLDoc.parentWindow.frames.item(1).document.getElementsByTagName("input")

iHTMLEle = iHTMLCol.item(0)

iHTMLEle.setAttribute("value", "test")

EndIf

EndSub

EndModule

I have the same code with thread.sleep and it works fine

Can we make it work without sleeping the thread?

It seems that we should. However, once that that is solved. How do I launch a page or frame within that page? Who is going to evaluate the doc.complete event, the same event  handler? unlikely. May be if we use shell windows  etc. but that adds a huge level  of complexity and it is doubtful that it will work well.

Antonio

 

Answer 57

The great burden with using Sleep() to synchronize threads is coming up with the argument value.  You'd like to make it as small as possible so you don't kill the UI for too long.  You want to make it as large as possible so you don't end  up sleeping too short.  That last requirement is the killer, especially with WebBrowser.  Not only do you rely on Windows giving the browser thread(s) enough time to finish their job, you also rely on the bandwidth of your Internet connection, the bandwidth the server  has, the size of the web page, the latency of the Internet connection anad the quality of the connection.

You can probably come of with an algorithm that calculates the sleep  duration.  You would have to use performance counters that gives you the CPU load  and the QoS API to measure the Internet connection performance.  Then cross your fingers that these measurements are still accurate after you navigated to the web page.  Needless to say, the amount of code  you'll need is big and tricky.

If you say "it works fine", you probably meant "it worked fine whenever I tried it".  The failure mode is nasty.  You'll end up not sleeping long enough when several things  go wrong at the same time.  You'd never be able to reproduce this later on when you try to resolve a customer's complaint.  You didn't state  your project's requirements.  My customers however universally dislike software that randomly fails without having any idea what they can do to prevent it from happening.  If I need to write more code to avoid disappointing my customers like this, I rarely  hesitate.
 

Answer 58

OK,

I finally discovered a use for Threading.Sleep.... but only if it is in a non-UI thread.  This code  is uber-critical.

PublicSub DoubleBeep()

System.Console.Beep(80, 150)

System.Threading.Thread.Sleep(50)

System.Console.Beep(80, 150)

EndSub

 

Answer 59

Nobugz,

I say  that thread.sleep works fine because it works fine in all cases I am concerned about referring to web pages loading.

sleep  within a While . end  While Statement

While dnc 'document not complete

Sleep(SleepTime)

EndWhile

The sleeptime value is almost irrelevant.

The important and critical fact is that this way I will always capture and control the end of web pages loading. However, to this day, nobody has shown me an event  handler that works well in all cases. That is the problem. We cannot control the inner workings of event handlers, very good in theory but not so good in practice.

 

Answer 60

Alsacedo,

I've constructed very complex webrowsers and use them constantly and I've never seen the problem you are referring to because I don't use the COM version of the webbrowser. I've also never had any problems  with events.

 

Answer 61

"Never had a problem" seems off-topic for this thread.  Perhaps you can start  a private  email conversation  with Alsacedo to compare notes about browser interfacing.  Let's focus on legit reasons to use Sleep().  Using a polling loop  on a property  with Sleep(1) in the loop is indeed a fix for flawed event  design.  Valid, but there are two specific problems  with your code  snippet. 

First, and this was discussed before, you assume that the loop exit condition  is reached in a reasonable amount of time.  Reasonable, as in, the user  barely notices the UI is dead.  That would typically not be the case with a browser.  I'd consider the high end  of reasonable 100 msec or less.  The "you can live with it but it sux" one second or less.  Getting these very forums to deliver a finished page took more than 30 seconds several times today.  That's not reasonable.  The fix is easy enough: use a Timer to poll the property value instead of a sleep  loop.

Secondly, and more seriously, you'll need to consider *all* of the possible property values in your loop test.  Testing for "navigation completed" works only 99.99% of the time.  The other 0.01% of the time, the data  transfer got aborted and the browser state  moved back  to "idle".  Now you've got a hung program  that takes Ctrl+Alt+Delete to bang back into shape.

FWIW: try the NavigateCompleted2 event. 
 

Answer 62

"Never had a problem" seems off-topic for this thread.  Perhaps you can start  a private  email conversation  with Alsacedo to compare notes about browser interfacing.  Let's focus on legit reasons to use Sleep().  Using a polling loop  on a property  with Sleep(1) in the loop is indeed a fix for flawed event  design.  Valid, but there are two specific problems  with your code  snippet. 

"Never had a problem" is exactly a short hand way of saying what you said here:

"Using a polling loop on a property with Sleep(1) in the loop is indeed a fix for flawed event design. "

I believe the real problem is the selection of COM to achieve Webbrowser functionality.

I think there has been a consensus in this thread  that threading  .sleep is used to coverage up problems.

For example, I used it above in conjunction with System.Console.Beep. I had to use a threading to begin with because System.Console.Beep is synchronous. That's a propblem. it need not be or the caller should have choice between synchronous and asynchronous  versions.

 

Answer 63

Hello Nobugz,

Thank you very much for your comments. I find them serious, helpful and to the point.

1. I am very aware of your fist comment. I navigate to many web pages in my applications. Often times the servers are not available or there are other issues. The way I go around it is: first, I start  a new process  for each first page navigated and/or  a timer  alerts the user  of a failed navigation in a specific page.

2. I am not very familiar with the aborted data  transfer potential problem that you mention. If it is what I understand, wouldn't the timer take care of it as well?

Let me be very clear, I am all for using events, avoiding COM objects, anything that results  in better programming. But as I have posted before, I still do not know why the following does now work:

It beeps several times. The browser is evaluated as completed several times before the page is fully loaded

PublicClass Form1

PrivateSub Form1_Load(ByVal sender  As System.Object, ByVal e As System.EventArgs) HandlesMyBase.Load

wb.Navigate("https://secure.netbank.com/login.htm")

EndSub

PrivateSub wb_DocumentCompleted(ByVal sender AsObject, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles wb.DocumentCompleted

Dim browser As WebBrowser = CType(sender, WebBrowser)

If browser.ReadyState <> WebBrowserReadyState.Complete Then

ExitSub

EndIf

Beep() 'It should beep only once

EndSub

EndClass


Lastly, not completely related but somewhat relevant, in my experience programming for real time trading applications, when I based my code  on captured events  for the API objects provided by the financial data provider it ended up in much slower response time, which rendered the code useless.

My point with this comment, is that since the event  capture is not under the control of the programmer, the programmer is at the mercy of how good that event capture is.

Antonio

 

Answer 64

ReneeC

"I finally discovered a use for Threading.Sleep.... but only if it is in a non-UI thread."

What do you mean with " ... but only if it is in a non-UI thread?

Sleeping a non-UI thread  is always allowed and in no way bad design! In fact, I think that it is much better than to use a timer  if you want to stop  a background  thread temporary!

Let's see what probably happens behind the scenes when a thread is timed. Note that the following is partly my guesswork as I have not been able to find precise information, so please correct me if I am wrong.

It is the timer ISR on IRQL 28, which discover that the time has expired. Since all thread switching is done by mean of a DPC routine on IRQL 2, the timer ISR is not allowed to put  the waiting thread in the active/ready queue. Instead it must post an APC routine (IRQL 1), which can do this. The documentation is rather unclear at this point. It says that each thread has both a kernel mode APC queue and a user  mode APC queue, but this does not make sense. APC routines in the queue of the thread are not activated until the thread is scheduled, so it is impossible for such a routine to reactivate the thread. I presume (pure guesswork) that there is only one kernel mode APC queue common to all threads (like the DPC queue). In this way, the kernel mode queue can be used to make a thread active so that it can be scheduled.

In case of a callback method, an APC routine for that method is also posted to the user mode APC queue of the thread.

Now, let's compare Sleep() with the use of a timer.

Sleep() will probably only need a single kernel mode APC routine to reactivate the thread.

In case of a timer, I presume that two APC routines are posted - one to the kernel mode queue to put the thread at the active/ready queue and one to the user mode queue to handle  the callback method. Besides, the necessary code  is much bigger than using Sleep().

My conclusion is that Sleep() is the most effective way to make a delay in a background thread! It "Wast nary a cycle or a byte" .

Can't we say that:

1) Sleeping a background thread is always allowed.

2) Sleeping the UI thread is only allowed to handle problems  coursed by flawed (event) design.

 

Answer 65

asalcedo wrote:

---- CLIP CLIP ----

PublicClass Form1

PrivateSub Form1_Load(ByVal sender  As System.Object, ByVal e As System.EventArgs) HandlesMyBase.Load

wb.Navigate("https://secure.netbank.com/login.htm")

EndSub

PrivateSub wb_DocumentCompleted(ByVal sender AsObject, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles wb.DocumentCompleted

Dim browser As WebBrowser = CType(sender, WebBrowser)

If browser.ReadyState <> WebBrowserReadyState.Complete Then

ExitSub

EndIf

Beep() 'It should beep only once

EndSub

EndClass

---- CLIP CLIP ----



Other Readers,
(My opinion)
The above code  is a sound and documented way of detecting document completion  with the WebBrowser control.  Calling Thread.Sleep is a hack since you don't know how long to wait.  Why guess?
COM may not be an issue  because as far as I know the WebBrowser control is just a managed wrapper on underlying COM components You should never call  Thread.Sleep from the UI thread!  But then again rules are  meant to be broken.  Seriously in a perfect world we would never have to block the UI thread-- in reality this isn't always possible (long database queries, etc.).  You should probably go to the extra work  of doing this kind of stuff in a background thread  and give the user  some sort of indication your application  isn't hung.  Oh and then add some sort of mechanism to detect if your background  thread is hung.
Calling Thread.Sleep is a background thread is always ok but as with any other programming task you have to ask yourself if you're doing it for the right reasons.  Polling is a great reason-- telling a thread go to sleep  for 5 min. and wakeup to do something useful can't be all bad.

Antonio,

I'm not sure if you work for this bank or are a hacker ;-). 

The code above is correct and will work most of the time (I'd say 99.9% but no stats.).  Pointing to one site out of millions (or is that billions yet?) that doesn't behave  in a certain way is hardly a case for tossing the whole idea. 

The reason you hear three beeps is because there are three 'Complete' documents being loaded and you should.   The site you refer to does two self-postbacks before displaying the main  page.  I'm not sure why this site is designed this way. It may be some sort of bot blocking idea or a browser detection scheme.
 

Answer 66

The site redirects twice.  The specific solution is simple, just use the final URL.  I don't see a general solution, Sleep() can't fix it reliably, nor your own "dnc".
 

Answer 67

1. I do not work for the bank and certainly, am not a hacker. I am happy to exchange CVs with relevant interested  parties.

2. This is certainly not an isolated case. I have encountered quite a few other cases where this routine would not work. I cannot share most of them though, because they are behind passwords.

When the site construction is "non standard", or when there are internal  page refreshes, redirections, etc. the routine does not always work. And that is the problem, one should not force the site construction to abide by the VB event capture requirements, but the other way around.

3. The solution of using the final URL does not work, the site requires to go through the first login page.

4. My sleep  routine, solves, this and all other cases. As I have posted long time ago here, it is just a matter of counting frames. Sleep while the frame count i(determined by doc complete event) is lower than the required value (total frame count), dnc=true, and continue as soon as dnc=false (frame count = total frame count). My solution does require finding out the total frame count in advance, but that is simple.

 

Answer 68

Carsten Kanstrup wrote:

Can't we say that:

1) Sleeping a background thread  is always allowed.

2) Sleeping the UI thread is only allowed to handle problems  coursed by flawed (event) design.

After a bit more consideration about this topic I would say,

1) Only use sleep  on a background  thread when it is absolutely needed, if possible it should be avoided by all means. Why? Imagine you have a highly loaded server application  that get events  raised in new thread all the time. If you sleep a background thread in this scenario you might end  up running out of available threads and any new events will get lost or delayed. You will degrade the performance of your application as it blocks resources (threads) that could be used.

2) Sleeping (blocking) the UI should never be acceptable. The UI thread should only be to handle  UI events and update the UI. If you have a component with flawed event  design you should either use a timer  or a new thread to work  around it.

I have made my share of mistakes with regards to this and as I have learned more I have corrected my mistakes. Today I always design  my applications to have an responsive UI and do work in other threads. 

It is accepted by most end-users to have to wait  for an application (the computer) to respond  but I know myself and others have ended up frustrated and get upset with applications that fails in letting me know what it is doing or responding to my user  actions like clicking buttons, resizing the window and similar.

The messages  that can not be handled when the UI thread is blocked will be put  in the queue for the application and handled when the message  loop is allowed to run. If you do not properly update the UI (disable controls) when you are busy a user might end up clicking around and creating a flood of actions and the application will handle those later and do things that wasn't the users  intention. To be hard on us developers  I would say there are no stupid users, only developers that doesn't take stupid usage into consideration. That a scenario is unlikely or "shouldn't" happen is no excuse to not develop code  that handles  it properly.

Windows and .NET have methods to avoid blocking a thread (UI thread) and possibilities to create new threads to do the work. It is very easy to do this in .NET and I see no reason why any developer  should learn that Thread.Sleep() is acceptable except for a few cases like a loop  in a game thread (not in the UI thread of course) to yield other threads.

Blocking a UI thread should never be seen as acceptable, not even as a workaround. That the sleep is so short that the user doesn't notice it is not an excuse to block the UI thread. The UI thread might need to respond to other messages from other applications and to block responding to it for a few ms is bad design.

What we usually mean with .NET is a platform that may run  on any software/hardware platform. This also means that we can not assume that our .NET application is running on a specific hardware platform unless explicitly specified when building it. If you do not use specific behaviour of the underlying software(OS)/hardware platform you should not assume anything about the actual behaviour of the runtime and the inner workings of base classes like System.Threading.Thread. This is made clear in the Thread class, it might behave differently if the underlying host (CLR) chooses to schedule the threads different than how it is done in the current Microsoft .NET implementation.

That Thread.Sleep() uses less resources than using a timer is most likely true  but it is not possible to determine what is most efficient as it depends on the specific scenario. If performance is an issue  I will refer to what was mentioned in the channel 9 interview with Rico Mariani. To develop for performance is to measure, measure, measure, measure, measure, measure, measure, measure, measure and measure the various approaches to be able to decide what is most efficient for your application. If Thread.Sleep() is performing better than using timers  than it might be the best choice. If no significant difference I would recommend to use a timer.

 

Answer 69

Year. For 200 mS the user  may end  up clicking around without a responce and the message  queue may reach its limit of 10,000 messages! That is really bad design, but the 5-10 sec. it takes to load  the CLR, perform the just in time compilation and load the program  is of course just natural!

Measure, measure, measure and measure is the the last way out for developers, who don't know what they are doing! For the moment I am working  on a big asynchronous  network for safety applications with approximately 2100 gates. That gives you up to 2**2100 possible combinations (not all gates are flip-flops) and I shall guarantee less than one undetected failure in 4.6x10**8 hours in according with IEC 61508 SIL 3. Do you really think that measure and test is the way to go? No, there is only one way: You better know what you are doing down to the smallest detail and convince yourself that you are right! This is the key to all reliable development. That's why I use so much time trying to dig down into Windows and find out what really goes on behind the scenes. Unfortunately, nobody seems to know!

 

Answer 70

"That is really bad design, but the 5-10 sec. it takes to load  the CLR, perform the just in time compilation and load the program  is of course just natural!"

It may take that long.... if you are running a 286. I NGEN my applications. This turns code  into native code and stores it in the gac keeping the regular image for metadata. This way there's very little difference between an ngenned assembly and a native mode image.

As for what's under the hood? How can we know exactly? Digital used to make operating  system sources available on microfiche and later on cd. We don't get to see windows  sources and when we do, it's no small wonder that windows internals looks like dreadful C. That's because it's written in C.

 

Answer 71

Oh, oh another major issue  for advocates of threading.Sleep

It very much highlights Andreas's last post.

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2056961&SiteID=1&mode=1

 

Answer 72

ReneeC

We do not all have a computer as fast as yours, but I think that the main  problem is the age of your Windows installation. Mine is 2-3 years old, but of course updated and I clean the registration data  base regulary with Advanced System Optimizer. However, we have just reinstalled Windows on my daughters PC, and its like getting a brand new PC with the double speed, so I guess I have to spend a whole day formating and reinstalling everything. That's what I call  a good user  experience and excellent programming!!!

Microsoft don't want their code  published. That's why they have encrypted it in C to be absolutely safe in case of a leak!!!

I am fully aware of the inaccuracy of Sleep(). Just read the chapter "Sleep" in my description of the serial port in our knowledgebase: http://www.innovatic.dk/knowledg/SerialCOM/SerialCOM.htm .

 

Answer 73

" That's why they have encrypted it in C to be absolutely safe in case of a leak!!!"

Carsten, I believe this is the funniest thing I have ever seen you say! What an incredible comment ! Big Smile

 

Answer 74

I have read all the posts and the comment concerning prime numbers is the closest link I can find to my problem.

I have written a Dialog Box application  in C++ which I would like to introduce for public  use. This implies a variety of windows  operating systems  and useage environments. I am keen that my application should be 'well-behaved'.

Attached to the Dialog is a recurring 300 msec timer  which invokes various functions. One of these consists purely of mathematical calculations and may take between 1 and 10 minutes to execute. In a previous application involving serial ports I cured a failure by inserting Sleep(0) at a strategic point.

I have experimented with Sleep(0) in my current application which works correctly with or without this function.

Serial ports aside, I would be grateful for the views of the thread  contributors on these questions:

1) Do I need to do anything because of my lengthy CPU-intensive calculations?

2) If so would inserting Sleep(0) at strategic points improve the program's behaviour towards other processes?

3) Would Sleep(1) be better?

4) In my particular circumstances would such a remedy be considered questionable design?

 

Answer 75

It's funny, I was thinking about this thread  today. I apologize for answering questions with questions but, what are you attempting to accomplish?

Why do you not use a background  worker on the lengthy computations? If it is the intensive consumption of cpu resources, you can always decrease the priority of the computational thread.

 

Answer 76

"Blocking a UI thread  should never be seen as acceptable, not even as a workaround. That the sleep  is so short that the user  doesn't notice it is not an excuse to block the UI thread. The UI thread might need to respond  to other messages  from other applications and to block responding to it for a few ms is bad design."

Do I ever agree.

We program  either syncronously (traditional programming) or asynchronously which is less tradtional. I tend to think of asynchronous  techniques as the techniques  a developer  would use. It's true  that sleeping a thread, a sychronous technique is poor. I'll agree with Andreas on just about everything he says. Unfortunately VB is largely, but not exclusively synchronous.
Renee
 

Answer 77

This is exactly where Application.DoEvents gets handy (see the other thread ). If you call  that before Sleep, there are no other waiting messages!


 

Answer 78

"Blocking a UI thread  should never be seen as acceptable, not even as a workaround. That the sleep  is so short that the user  doesn't notice it is not an excuse to block the UI thread. The UI thread might need to respond  to other messages  from other applications and to block responding to it for a few ms is bad design."

Do I ever agree.

We program  either syncronously (traditional programming) or asynchronously which is less tradtional. I tend to think of asynchronous  techniques as the techniques  a developer  would use. It's true  that sleeping a thread, a sychronous technique is poor. I'll agree with Andreas on just about everything he says. Unfortunately VB is largely, but not exclusively synchronous.
Renee

Do I ever agree!

The term synchronous programming is used here to describe what I always refer to as procedure-driven programming.
The term asynchronous programming is used here to describe what I always refer to as object-oriented programming.
 

Answer 79

Another term we used to use was "event-driven programming". Of course we used it and knew about it, we just had different terminology than OOP. The fact that you know the difference between synchronous and asynchronous  techniques, says a lot for you!
Renee
 

Answer 80

Thanks.  I've been using "object-oriented' for only a few years.
Ever since I dove head first into .NET and banged my head on design  patterns.
Prior to that I was calling  by a name similar to yours, "interrupt-driven programming".
 

Answer 81

Certainly I understand the term in a profound way although "interupt driven  communications" does not quite cover it which is why DEC called  it asynch or event  driven programming.
Renee
 

Answer 82

I can see that.  My roots are more on the hardware end  of things. 
Started off designing CPUs out of TTL chips on wire-wrapped motherboards.
We were generating hardware and software IRQs.

Mark the best replies as answers. "Fooling computers since 1971."
 

Answer 83

We did that in the VAX also. Although I understood hardware I was on the software engineering side of things. I sure thought  we'd be friends, now I'm certain of it.
Renee
 

Answer 84

I just wanted to say thank you reneec

I really appreciate the explanation,  i would really like to see more info on other points as well.

So many times i see - don't do this or don't do that.  And the answer although really long, does not quite explain why.

And that may also be because the answer is over out heads.

 

This thread  is a perfect example for many:  it shows you what you shouldn't do and now here is how you should do it.

And why not to do it is explained very well.

And even better it has "Real World" examples.

Wonderful

 

Many times i feel like the knowledge that you more experienced  programmers have is just sitting idle and teased by throwing simple code  bits at us.  Which many times that's what were askin for.  And even though it gets you to the next point, many don't even know how or why it works.  It just does.  And i see the frustration all the more experienced have when us beginners just don't get it.  Even though the answer you gave is the right one, we are still looking for the answer even though you gave it because we just don't understand how to put  it together.

____________________

[url=http://www.dietpillsforweightloss.com/]www.dietpillsforweightloss.com[/url]

[url=http://hghzonecenter.com/]Human Growth Hormone[/url]


 
 
 

<< Previous      Next >>


Microsoft   |   Windows   |   Visual Studio   |   Follow us on Twitter