C# Command to Wait a Specified Period of Time

R

Robert E. Flaherty

What is the C# command to wait for a specified period of time?

I am writing a windows service that will process a file once it has beed
created or changed. I'm using the fileSystemWatcher to detect when a
specific file has been created or changed. That works fine to a point. The
event does fire when the file is being created or changed but I then blow up
when I attempt to open the file because the creation or changing has not
finished.

Using the try/catch structure, I am wanting to attempt to open the file. If
it is still being used, then wait a minute and try again. I rather use a
command (assuming that one exists) to sit there for say a minute and try
again.

Using a timer evolves a callback. I was hoping for a simple solution.
 
M

Michael C

Robert E. Flaherty said:
What is the C# command to wait for a specified period of time?

I am writing a windows service that will process a file once it has beed
created or changed. I'm using the fileSystemWatcher to detect when a
specific file has been created or changed. That works fine to a point.
The
event does fire when the file is being created or changed but I then blow
up
when I attempt to open the file because the creation or changing has not
finished.

Using the try/catch structure, I am wanting to attempt to open the file.
If
it is still being used, then wait a minute and try again. I rather use a
command (assuming that one exists) to sit there for say a minute and try
again.

Using a timer evolves a callback. I was hoping for a simple solution.

Something like this will work. You can't sleep for 60 seconds because your
service won't stop for 60 seconds if someone pushes stop.

for(int i = 0; i < 60; i++)
{
System.Threading.Thread.Sleep(1000);
if(StoppHasBinPushed) break;
}
 
P

Peter Duniho

[...]
Using the try/catch structure, I am wanting to attempt to open the
file. If
it is still being used, then wait a minute and try again. I rather use a
command (assuming that one exists) to sit there for say a minute and try
again.

Using a timer evolves a callback. I was hoping for a simple solution.

What's not simple about using a timer?

Timer timer = new System.Windows.Forms.Timer();

timer.Interval = 60000;
timer.Tick += delegate
{
if (!fRetry || TryOpenFile())
{
timer.Stop();
}
};
timer.Start();

Where the method "TryOpenFile()" contains your logic to attempt the
operation with a try/catch exception handler, returning "true" on success,
"false" on failure. The "fRetry" flag is provided for convenience, to
support canceling as suggested by Michael. Declare it somewhere else,
initialize to "false", set it to true if you want to cancel the operation
before it's completed.

Alternatively, you could just store a reference to the timer elsewhere and
stop the timer explicitly when the operation needs to be canceled.

I don't see the point in code like Michael's. Just as it doesn't make
sense to block for 60 seconds, preventing the user from canceling the
operation until then, it also doesn't make sense to block for 1 second,
preventing the user from canceling the operation until then. You
shouldn't block at all. Just set up a timer, try the operation on every
tick, and once it succeeds, stop the timer.

It's really not that complicated. The number of lines of code is about
the same as Michael's proposal, and this implementation has the added
benefit of not doing something bad like blocking the GUI thread for
extended periods of time.

You could, of course, put the operation on a whole new thread and let it
sit and wait there. Then you could just call Sleep(60000) and perform
whatever logic, including checking for a successful file open as well as
having the operation canceled, in a loop there:

while (!fRetry)
{
if (TryOpenFile())
{
break;
}
Thread.Sleep(60000);
}

But then you need to put that code in a thread somewhere, as well as deal
with any cross-thread issues. I'd hardly say that's simpler solution than
using a timer.

Pete
 
M

Michael C

Peter Duniho said:
I don't see the point in code like Michael's. Just as it doesn't make
sense to block for 60 seconds, preventing the user from canceling the
operation until then, it also doesn't make sense to block for 1 second,
preventing the user from canceling the operation until then. You
shouldn't block at all. Just set up a timer, try the operation on every
tick, and once it succeeds, stop the timer.

Doesn't this apply equally to all code that blocks then? Most database
lookups of any complexity will block for 1 second. In this situation we can
just reduce the interval to 1/10th. While your code is a similar number of
lines it is more complex. I can't say I'm a big fan of those inline
delegates.
 
P

Peter Duniho

Doesn't this apply equally to all code that blocks then? Most database
lookups of any complexity will block for 1 second. In this situation we
can
just reduce the interval to 1/10th. While your code is a similar number
of
lines it is more complex. I can't say I'm a big fan of those inline
delegates.

Why not? They work quite well, especially when you take advantage of the
variable-capturing they provide. They can greatly simplify your code, and
IMHO this is a good example of them doing just that. An implementation
not using an anonymous method would require at least twice as much
effort. Not that the effort would be great in either case, but the
alternative is less readable as well.

I would also disagree that my code is "more complex". It only appears
that way because you left out at least a couple of statements that are
required: the line that actually attempts to do the file open, and the
line that (ick!) calls DoEvents() so that you can respond to user input.

I personally find my code _simpler_, not more complex. It's not
re-entrant and it doesn't cause the thread to get stuck in the Form's
event-handling procedure for extended periods of time.

In any case, yes..."this" does apply equally to all code that blocks.
IMHO, it's not a good idea to put blocking code in the GUI thread. For
some "quick and dirty" or extremely simple applications it might be okay,
but it's not something that should show up in anything serious, and this
is especially true when the blocking could be significantly long.

Pete
 
M

Misbah Arefin

while(true)
{
try
{
TryOpenFile(e.Name);
ProcessFile(e.Name);
break;
}
catch(Exception ex)
{
System.Threading.Thread.Sleep(1000);
continue;
}
}
 
M

Michael C

Peter Duniho said:
Why not? They work quite well, especially when you take advantage of the
variable-capturing they provide. They can greatly simplify your code, and
IMHO this is a good example of them doing just that. An implementation
not using an anonymous method would require at least twice as much
effort. Not that the effort would be great in either case, but the
alternative is less readable as well.

It's not really clear what's going on. In order to be called back into they
must really be compiled as a function but they can access the original
function's local variables. It's not worth the code it saved imo.
I would also disagree that my code is "more complex". It only appears
that way because you left out at least a couple of statements that are
required: the line that actually attempts to do the file open, and the
line that (ick!) calls DoEvents() so that you can respond to user input.

Complexity and line count are not the same thing. You create a timer object
and a delegate.
I personally find my code _simpler_, not more complex. It's not
re-entrant and it doesn't cause the thread to get stuck in the Form's
event-handling procedure for extended periods of time.

As I said, line count does not equate to complexity.
In any case, yes..."this" does apply equally to all code that blocks.
IMHO, it's not a good idea to put blocking code in the GUI thread. For
some "quick and dirty" or extremely simple applications it might be okay,
but it's not something that should show up in anything serious, and this
is especially true when the blocking could be significantly long.

I doubt there is an app in existance that puts every single call longer than
1 second on a seperate thread. It's probably a good ideal but is just that.

Michael
 
P

Peter Duniho

It's not really clear what's going on. In order to be called back into
they
must really be compiled as a function but they can access the original
function's local variables. It's not worth the code it saved imo.

Well, I guess you're entitled to your opinion. IMHO, nothing could be
clearer than putting all of the relevant code in one place, rather than
making someone go looking for it.
Complexity and line count are not the same thing. You create a timer
object
and a delegate.

And you call DoEvents(), which hides a remarkable degree of complexity
(such as the re-entrant behavior I mentioned).
As I said, line count does not equate to complexity.

I'm not saying it does. I'm saying you glossed over the complexity in
your own suggestion.
I doubt there is an app in existance that puts every single call longer
than
1 second on a seperate thread.

Every .NET application I've written falls into that category. So I know
there's at least some applications in existence that qualifies.
It's probably a good ideal but is just that.

What's the point of having a "good ideal" if you don't actually strive to
achieve the ideal?

Pete
 
M

Michael C

Peter Duniho said:
Well, I guess you're entitled to your opinion. IMHO, nothing could be
clearer than putting all of the relevant code in one place, rather than
making someone go looking for it.

IMO it's not MUCH better to have the code in a seperate function. In your
example we actually exit the function but jump back into it right in the
middle!! Yuk!
And you call DoEvents(), which hides a remarkable degree of complexity
(such as the re-entrant behavior I mentioned).

Naturally either solution is potentially re-entrant.
I'm not saying it does. I'm saying you glossed over the complexity in
your own suggestion.

Having a message queue is part of any windows app. Allowing that to process
is minor.
Every .NET application I've written falls into that category. So I know
there's at least some applications in existence that qualifies.

So you start a new thread to show a form? :) Every application I've ever
used, including stuff from the big names, blocks the GUI at one point or
another. I'd be suprised if I couldn't find somewhere your apps didn't do
the same.
What's the point of having a "good ideal" if you don't actually strive to
achieve the ideal?

Generally they fall over in reality.

Michael
 
M

Michael C

Michael C said:
IMO it's not MUCH better to have the code in a seperate function. In your
example we actually exit the function but jump back into it right in the
middle!! Yuk!

That should read "it's much better" :)

Michael
 
P

Peter Duniho

IMO it's not MUCH better to have the code in a seperate function. In your
example we actually exit the function but jump back into it right in the
middle!! Yuk!

The anonymous method is not part of the method in which it's declared.
It's a complete method unto itself. The execution of the anonymous method
does not "jump back into" the method in which it's declared.

Perhaps the reason you don't like anonymous methods is that you have
failed to conceptualize them in a useful way. It's true that when you
don't understand something, it seems a lot less useful than when you do.
Naturally either solution is potentially re-entrant.

Negative. An anonymous method doesn't have any of the re-entrancy issues
that calling DoEvents() does.
Having a message queue is part of any windows app.

Having a _synchronous_ message queue is a normal part of any Windows
application.
Allowing that to process is minor.

"Minor" is in the eye of the beholder. Suffice to say, I disagree with
the claim that completely changing the messaging architecture of an
application is a "minor" alteration.

Pete
 
M

Michael C

Peter Duniho said:
The anonymous method is not part of the method in which it's declared.
It's a complete method unto itself. The execution of the anonymous method
does not "jump back into" the method in which it's declared.

Perhaps the reason you don't like anonymous methods is that you have
failed to conceptualize them in a useful way. It's true that when you
don't understand something, it seems a lot less useful than when you do.

Granted I don't understand what's going on under the hood but that is part
of the problem. As I said previously it must compile to a seperate function
but contains another functions local variables. I say again Yuk!
Negative. An anonymous method doesn't have any of the re-entrancy issues
that calling DoEvents() does.

I don't see how you can say that. The only way mine can be re-entrant is if
the user clicks the GO button again. Yours suffers the same problem as far
as I can see as someone can kick off the entire process again if they like.
"Minor" is in the eye of the beholder. Suffice to say, I disagree with
the claim that completely changing the messaging architecture of an
application is a "minor" alteration.

From the programmers pov doevents is quite simple. While your method isn't
much more complicated it still is.

BTW, who said anything about DoEvents. It was you who added the idea of
using DoEvents. And who said anything about a GUI, this is a windows
service.

Michael
 
P

Peter Duniho

Granted I don't understand what's going on under the hood but that is
part
of the problem.

IMHO, it's poor practice to denigrate a language feature if you don't
fully understand it.
As I said previously it must compile to a seperate function
but contains another functions local variables. I say again Yuk!

And I say "Aha!" Variable capturing is one of the things that makes
anonymous methods so useful.
I don't see how you can say that. The only way mine can be re-entrant is
if
the user clicks the GO button again.

Actually, it's re-entrant the moment you call DoEvents(). "Under the
hood", you've got a window's "window proc" (aka "wndproc") that is busy
handling a specific window message, having been called from a message pump
loop. When you call DoEvents(), that enters an entirely new message pump
loop, which will in turn call the window proc again.

Just because you don't see the re-entrancy, that doesn't mean it doesn't
exist, nor does it mean there's no potential for a problem. The user
clicking the same button again isn't the issue, and in fact I would expect
that a proper program would disable the button if it's inappropriate for
it to be clicked. It's the question of the fact that your window hasn't
finished handling one window message, and now may be asked to process any
number of new window messages.

It's an intractable design problem inherent in calling DoEvents(). It
leads to code that is at best difficult to maintain, and at worst can
contain subtle bugs that are difficult to find, never mind solve.
Yours suffers the same problem as far
as I can see as someone can kick off the entire process again if they
like.

Mine ensures that the Form class is handling one message at a time. You
can always _add_ re-entrancy to the code, but it's not inherent in the
anonymous method technique, while it is inherent in using DoEvents().
From the programmers pov doevents is quite simple. While your method
isn't
much more complicated it still is.

DoEvents() only _seems_ to be simple. The fact that you believe it
actually _is_ simple is a symptom of the basic problem. DoEvents() has
fooled you into thinking that it's simple, when in fact it's actually
quite a complicated addition to the architecture.
BTW, who said anything about DoEvents. It was you who added the idea of
using DoEvents. And who said anything about a GUI, this is a windows
service.

I can only laugh at this point. It appears that I missed an important
aspect of the original question (it's a service), and you missed an
important aspect of my reply: I used the System.Windows.Forms.Timer class
in a context where that class isn't useful or desirable at all.

That said, consider "GUI" as a general talking point if you will. The
issue here is whether the thread is available to process other activity.
You wrote "You can't sleep for 60 seconds because your service won't stop
for 60 seconds if someone pushes stop", so obviously you anticipate doing
_something_ inside that loop that allows the service to process other
input.

Whether that something is DoEvents() or something else, the same basic
issues apply though I agree that some specifics that apply to DoEvents()
obviously wouldn't in other implementations. In particular, there are
still re-entrancy issues and depending on the architecture of the service
they could be even more complex than those introduced by the use of
DoEvents() in a Forms application.

Now, in the context of a service, timers get more complicated than when
using System.Windows.Forms.Timer in a Forms application. All of what I
wrote was aimed specifically at a Forms application, and that's where the
System.Windows.Forms.Timer class is especially helpful. It ensures that
execution of the timer event handler is synchronized with other activity
in the GUI thread. Obviously that benefit doesn't apply when using some
other timer mechanism.

Because of that, in this situation my recommendation would be to run the
"retry" logic on a different thread, per my alternate suggestion in my
original reply.

There is still no need, nor is it desirable, to have any thread wait 60
seconds by actually waiting for 1 second 60 times. Just make the thread
wait 60 seconds and be done with it. If the process needs to be available
to do other work, handle that other work in a different thread.

Pete
 
M

Michael C

Peter Duniho said:
IMHO, it's poor practice to denigrate a language feature if you don't
fully understand it.

I don't need to understand all details under the hood to dislike a feature.
I'm sure you dislike plenty of features without looking at the assembler.
It's an intractable design problem inherent in calling DoEvents(). It
leads to code that is at best difficult to maintain, and at worst can
contain subtle bugs that are difficult to find, never mind solve.

Great. The end result is the same though, both methods can suffer
re-entracny. You're trying a little too hard to find a problem here when
none exists.
Mine ensures that the Form class is handling one message at a time. You
can always _add_ re-entrancy to the code, but it's not inherent in the
anonymous method technique, while it is inherent in using DoEvents().

Rubbish, the exact same issue exists. The only possible problem is the user
clicking the button again and both methods have this problem.
DoEvents() only _seems_ to be simple. The fact that you believe it
actually _is_ simple is a symptom of the basic problem. DoEvents() has
fooled you into thinking that it's simple, when in fact it's actually
quite a complicated addition to the architecture.

Maybe it is under the hood but from my pov (the programmers) it is very
simple.
I can only laugh at this point.

That is where I exit this thread.

Michael
 
P

Peter Duniho

I don't need to understand all details under the hood to dislike a
feature.
I'm sure you dislike plenty of features without looking at the assembler.

Apple and oranges.
Great. The end result is the same though, both methods can suffer
re-entracny. You're trying a little too hard to find a problem here when
none exists.

I didn't have to try hard at all. I have no idea what you're talking
about.
Rubbish, the exact same issue exists. The only possible problem is the
user
clicking the button again and both methods have this problem.

Wrong. As I already explained, I expect the button to be disabled if
clicking it is a problem. That's not what I'm talking about.
Maybe it is under the hood but from my pov (the programmers) it is very
simple.

The behavior is not.
That is where I exit this thread.

Knee-jerk. You obviously didn't even read what I wrote. The laughing was
at myself.

Pete
 
S

Scott Roberts

Maybe it is under the hood but from my pov (the programmers) it is very
simple.

It may be simple to call DoEvents(), but as Peter has already said, it will
be very difficult (if not impossible) to find and correct all of the
problems you have caused by doing so.
 
S

Scott Roberts

The anonymous method is not part of the method in which it's declared.
It's a complete method unto itself. The execution of the anonymous method
does not "jump back into" the method in which it's declared.

The "complexity" (if you will) comes from having a method declared right in
the middle of an executing code block. While I agree that this is not a huge
source of complexity, it *is* less readable (IMO, of course).
 
J

Jon Skeet [C# MVP]

Michael C said:
IMO it's not MUCH better to have the code in a seperate function. In your
example we actually exit the function but jump back into it right in the
middle!! Yuk!

Anonymous functions take a little bit of a change of mindset, but they
really are incredibly useful.

You really are missing out (particularly in C# 3) if you decide to
avoid them all the time, rather than taking the trouble to understand
them. They *can* cause subtle bugs, but most of the time they're
absolutely fine, and can make code much, much simpler.
 
J

Jon Skeet [C# MVP]

Scott Roberts said:
The "complexity" (if you will) comes from having a method declared right in
the middle of an executing code block. While I agree that this is not a huge
source of complexity, it *is* less readable (IMO, of course).

Let's consider an example here, in C# 3. Suppose we want to write a
method which takes an IEnumerable<Person> and returns another
IEnumerable<Person> which has filtered out everyone under a certain
age, which is also a parameter to our method, i.e.:

public IEnumerable<Person> FilterByAge(IEnumerable<Person> input,
int ageLimit)

There are two obvious ways of doing this:
1) Use an iterator block. That's actually doing more behind the scenes
than an anonymous method.

2) Use the "Where" extension method, which accepts a delegate. Now we
have three choices:

a) Use an "old school" delegate. We need to be able to provide the age,
so we've got to write a whole extra class:

public class AgeFilter
{
int ageLimit;

public AgeFilter(int ageLimit)
{
this.ageLimit = ageLimit;
}

public bool Filter(Person p)
{
return p.Age < ageLimit;
}
}

then we implement our method with:

public IEnumerable<Person> FilterByAge(IEnumerable<Person> input,
int ageLimit)
{
AgeFilter filter = new AgeFilter(ageLimit);
return input.Where (filter.Filter);
}

b) We can use an anonymous method. No need for an extra class in our
source code - the compiler will generate it:

public IEnumerable<Person> FilterByAge(IEnumerable<Person> input,
int ageLimit)
{
return input.Where(delegate (Person person)
{ return person.Age < ageLimit; }
);
}

c) We can use a lambda expression:

public IEnumerable<Person> FilterByAge(IEnumerable<Person> input,
int ageLimit)
{
return input.Where(person => person.Age < ageLimit);
}


Now, do you really think that solution a is more obvious in its
intention than solutions b or c?
 
S

Scott Roberts

Jon Skeet said:
Now, do you really think that solution a is more obvious in its
intention than solutions b or c?

No, I think solutions b and/or c are more obvious.

Of course, in your contrived example the anonymous method executes "in-line"
with the declaring code. In Peter's example, the anonymous method executes
on a timer event.

You'll also note that I have already stated that it's not that big of a
deal, but it is slightly less readable. And of course, that's just my
opinion.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top