Safe multithreading in ASP.Net

W

who be dat?

Consider the following code which enables multithreading in an ASP.Net
application I'm writing:

Code in global.asx Application_start subroutine, Threadnotify is declared
Globally as a new thread where it uses the address of EmailNotify below:

ThreadNotify.IsBackground = True

ThreadNotify.Start()

--------

Public Sub EmailNotify()

Dim emails As New ForumEmail

Do While ContinueNotify 'boolean value set to True so loop will continue

emails.EmailNotify()

Thread.Sleep(notifyinterval * 60000) 'notifyinterval is set via app
settings in web.config file

Loop

End Sub

--------------------

From global.asx file in Application_End subroutine

ThreadNotify.Abort()



As you can probably tell, what happens is Threadnotify is started when the
application starts. The subroutine simply loops through and calls a
subroutine then it pauses in intervals of minutes. Good this works.
Bad this works too good. Problem is, when does this thread get
terminated? I can set the boolean notify in the loop to false so the thread
will reach the end of it's code and it will terminate. However, beyond this
I have concerns. I'm writing an application on my machine and testing it.
I can't get that thread to stop unless I set the boolean value to false in
that loop which is bad. When I end the debug execution of the app, the
thread continues and it doesn't stop. Heck, I can stop the IIS Service and
the thread still continues to execute. How do I know it's executing. The
goal of this thread is to send emails. I'm getting emails indicating which
tells me this thread is still running.

This leads to a larger issue. When I release this application for others to
use, how can I ensure this thread won't keep running even though a user
might end the web service? This sucker just keeps going and going.

Suppose I upload this to a production webserver. The thread starts and
executes fine. Suppose I make some changes to the application code and copy
the necessary files to the production webserver. Will the thread from the
previous versoin of the website continue while a new thread is started by
the updated code i.e. there will be two threads doing the same thing?

The way this thread runs, I believe I can stop the webservice and destroy
the webapplication. The thread would still run. This isn't acceptable.
How do I ensure this thread stops?

What is this thread running under? I would've thought the thread would run
under IIS and consider IIS to be the parent process. However, I'm
terminating IIS and this thread still keeps going. What is it running
under?

Ultimately, when the heck does this thread terminate?! The only thing I can
do to stop this thread is to reboot the machine! I'm scared to publish this
to my website as it may start up and never stop until they reboot their
machines.

This thread is supposed to send emails after a pause determined by the user.
Is there another way to do this? I though about using a timer that, when X
amount of minutes passed, then the event would fire. I could capture that
event and execute the email code. I wasn't sure how to do this though.
Suggestions?



Thanks

Chris Smith
 
A

Alvin Bruney [MVP]

couple issues.

ThreadNotify.IsBackground = True
this line instructs the thread to cease all activity when the application
ends. the application doesn't end when the debugger terminates, or the
webpage is closed or session ends. so your thread will keep running.

in the event of an iis reset, your thread will end because the application
ends, but it starts as soon as a request is made which is probably why you
are seeing emails after it has ended. it's not possible for the thread to be
running when the application has ended.

basically, you need to rethink your logic because threads will always be
running as long as the webpage has received an initial request. these
threads won't stop until iis resets or asp.net detects a change to a
configuration file.
 
J

John Saunders

who be dat? said:
Consider the following code which enables multithreading in an ASP.Net
application I'm writing:
....

Suggestions?

Yes. I suggest that you immediately cease all idea of using multithreading
with ASP.NET! Pretend that threads just don't exist, or that any attempt to
use threads with ASP.NET will cause horrible problems for you (which is
true).

Now, since nobody ever listens to such simple-minded suggestions, I'll try
to explain. On every request, ASP.NET instantiates your Page object,
processes it in several phases, then destroys it. Nothing that was on the
page will remain after the request completes. This makes it very hard on any
threads you've started during the request, if they do not terminate before
the request terminates, as they will be operating on a dead page.

The request will not wait for your threads. It doesn't have any idea that
they exist. The fact that your threads still exist and are still referencing
objects you created on the page will not save you - the objects may still
exist, but their state may invalid. This especially goes for any objects
created or manipulated by ASP.NET, since ASP.NET believes that the request
is over, and so is unlikely to continue to maintain the state of any objects
which belong to it.

I strongly recommend that you learn some of the details of what ASP.NET is
doing behind the scenes. Take a look at the following MSDN articles:

The ASP.NET Page Object Model
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/htm
l/aspnet-pageobjectmodel.asp?frame=true)



Developing ASP.NET Server Controls
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/ht
ml/cpconkeyconceptsinwebformscontroldevelopment.asp)
 
R

Rick Strahl [MVP]

Hi Chris,

Why is your thread running in this endless loop? Shouldn't there be some
logic to terminate the loop in and of itself? unless you're planning on
creating some sort of pool manager for your thread(s) there needs to be
self-destruct logic in your threads. If you do have some such mechanism you
can use a static property on some global (Global works) or static property
that can get triggered by Application shutdowns.

As others have said here I'd be very wary of firing threads out of ASP.Net
unless you know exactly what you're doign. If everything's self contained
and doesn't rely on anything of the page (which usually means copyin what
you need to a new object), then running additional threads is safe. But you
still need an exit strategy of some sort. Do what you need to do - slow or
otherwise and get out!

The other thing that you can do is look into async Web requests, which are
relatively easy to set up and run. But there's really no huge benefit for
this over just tieing up an ASP.Net thread either in the first place.

+++ Rick ---

--

Rick Strahl
West Wind Technologies
http://www.west-wind.com/
http://www.west-wind.com/weblog/
http://www.west-wind.com/wwThreads/
 
D

Duncan Kennedy

Hi Chris,

Perhaps you would be better off using a message queue? Throwing the
necessary data into the queue as you need and writing a .NET service to
poll the queue. Any threads would be contained in a block of non
ASP.NET code with more intuitively comprehensible behaviour when it
comes to starting and stopping.

Just a thought without a think through...

Regards,

Duncan Kennedy
 
C

Chris R. Timmons

Yes. I suggest that you immediately cease all idea of using
multithreading with ASP.NET! Pretend that threads just don't
exist, or that any attempt to use threads with ASP.NET will
cause horrible problems for you (which is true).

Now, since nobody ever listens to such simple-minded
suggestions, I'll try to explain. On every request, ASP.NET
instantiates your Page object, processes it in several phases,
then destroys it. Nothing that was on the page will remain after
the request completes. This makes it very hard on any threads
you've started during the request, if they do not terminate
before the request terminates, as they will be operating on a
dead page.

The request will not wait for your threads. It doesn't have any
idea that they exist. The fact that your threads still exist and
are still referencing objects you created on the page will not
save you - the objects may still exist, but their state may
invalid. This especially goes for any objects created or
manipulated by ASP.NET, since ASP.NET believes that the request
is over, and so is unlikely to continue to maintain the state of
any objects which belong to it.

I strongly recommend that you learn some of the details of what
ASP.NET is doing behind the scenes. Take a look at the following
MSDN articles:

The ASP.NET Page Object Model
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us
/dnaspp/htm l/aspnet-pageobjectmodel.asp?frame=true)

Developing ASP.NET Server Controls
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us
/cpguide/ht ml/cpconkeyconceptsinwebformscontroldevelopment.asp)

John,

I disagree. When done properly, threads can be easily and
effectively implemented in ASP.Net. They are especially useful in
getting around timeout problems associated with long running
proceses. Here's an article that shows how:

http://www.ftponline.com/vsm/2002_11/magazine/features/chester/defaul
t.aspx

or

http://tinyurl.com/ysaf7


Chris.
 
C

Chris R. Timmons

Consider the following code which enables multithreading in an
ASP.Net application I'm writing:

Code in global.asx Application_start subroutine, Threadnotify is
declared Globally as a new thread where it uses the address of
EmailNotify below:
<SNIP/>

Chris,

Do you really want to start a new thread for each application
instance? Or do you just want a maximum of one thread running as
long as there is at least one application instance running?

Maybe you could also tell us more about the functional requirements
of your app. Do users log into/out of your app? If so, when do you
want the thread(s) to run - when the app starts or when the first
user logs in? If users are required to log in, then maybe you could
shut down the thread(s) when the user logs out, instead of when the
app ends.
 
W

who be dat?

Alvin Bruney said:
couple issues.

ThreadNotify.IsBackground = True
this line instructs the thread to cease all activity when the application
ends. the application doesn't end when the debugger terminates, or the
webpage is closed or session ends. so your thread will keep running.

in the event of an iis reset, your thread will end because the application
ends, but it starts as soon as a request is made which is probably why you
are seeing emails after it has ended. it's not possible for the thread to be
running when the application has ended.

This has me scratching my head because I've tested this several times. I
shut down IIS thru MMC console and I'm still receiving emails. I left IIS
turned off (at least stopped the service) and it's still going. The only
way I can stop the thread is to reboot. See a response I'm about to leave
to Chris R. Timmons for more info.

Thanks!

Chris Smith
 
A

Alvin Bruney [MVP]

in your subject line for the email, put the timestamp so you know when the
email was sent. then you can verify whether or not a thread is running or
not by examing this timestamp.
 
W

who be dat?

Chris R. Timmons said:
Chris,

Do you really want to start a new thread for each application
instance? Or do you just want a maximum of one thread running as
long as there is at least one application instance running?

Maybe you could also tell us more about the functional requirements
of your app. Do users log into/out of your app? If so, when do you
want the thread(s) to run - when the app starts or when the first
user logs in? If users are required to log in, then maybe you could
shut down the thread(s) when the user logs out, instead of when the
app ends.


Hi Chris,

I'm writing a bulletinboard application in order to learn ASP.Net. I've got
it going pretty good. You can see it at http://www.dotnetforum.net as a
matter of fact if you'd like. I'm now adding a new feature on my machine at
home. Once this feature is fully implemented and debugged, I will transfer
the update to the previously mentioned website. This feature will email
users when someone responds to a topic the user is watching letting that
user know someone has responded to a topic and provide a link the user can
click on to view the topic in their web browser. This is feature is fairly
typical among such applications.

I could just run through the code to send the emails to users everytime a
user responds which after my experiment in multi-threading I'm considering
doing. However, I was concerned about performance on a busy website.
Everytime a user responds, the code will look through the tables, figure out
all the emails it needs to send, and send all the emails. Not to bad if one
or two users are online at once responding away. But, I became concerned
about performance when there would be a large number of users online
responding multiple times. The site would go through the email routine
every time a large amount of users responded to the site. When a single
user responds, that user might spawn a lot of emails to be sent out which
means they would have to wait till the emails were sent if there are a lot
people watching a particular topic. Add in the fact lots of people could be
responding at the same time and it could hurt website performance not to
mention individual users might notice the wait as the data was retrieved and
emails were sent. They would have to wait for those actions to complete
till they could move in the website. I thought I could help the site out by
creating a thread that ran in the background. The thread would search the
tables, send out the emails it needed to, then sleep for X amount of minutes
where X is determined by an app setting value in web.config. It's working
great. Problem is, the dang thread never terminates.

What you think about this? I suppose I could just write a thread like the
following:

Dim ThreadNotify as Thread 'declared in a code module as a public object to
be accessed anywhere

When user responds the message is posted then this bit of code is executed:

..
..
..
ThreadNotify = New Thread(New ThreadStart(AddressOf EmailNotify))
ThreadNotify.Start()
..
..

..

Public Sub EmailNotify()

Dim emails As New ForumEmail

Do

emails.EmailNotify()

End Sub



Thing is, everytime someone responds a new thread will be created. But,
once the code for emailnotify reached the end sub statement, the thread
would terminate, right? I'd rather not create a thread everytime someone
responds but at least the grunt work would get done in another process and
hopefully the user won't notice it.



Can you think of a better way to do this? Thanks!

Chris Smith
 
W

who be dat?

A time is attached to the email already. I'm not sure if the SMTP server is
attaching it or not but there's one there. I've currently got the interval
for the thread set to 5 minutes. After observing the frequency of the sent
emails, looking at the time stamps on the emails, and turning IIS off, the
thread never stops which has me scratching my head. Part of me thinks the
thread is actually part of the OS since the application is running under IIS
and IIS is run under the operating itself. Since the thread is running
under started by an IIS app, the thread is actually started by the OS
itself. As long as the OS is running, the thread runs. Did you notice my
other response to Chris Timmons yet?

Thanks!

Chris Smith

Alvin Bruney said:
in your subject line for the email, put the timestamp so you know when the
email was sent. then you can verify whether or not a thread is running or
not by examing this timestamp.

--
Regards,
Alvin Bruney
[ASP.NET MVP http://mvp.support.microsoft.com/default.aspx]
Got tidbits? Get it here... http://tinyurl.com/27cok
who be dat? said:
to
be

This has me scratching my head because I've tested this several times. I
shut down IIS thru MMC console and I'm still receiving emails. I left IIS
turned off (at least stopped the service) and it's still going. The only
way I can stop the thread is to reboot. See a response I'm about to leave
to Chris R. Timmons for more info.

Thanks!

Chris Smith
 
J

John Saunders

Chris R. Timmons said:
John,

I disagree. When done properly, threads can be easily and
effectively implemented in ASP.Net. They are especially useful in
getting around timeout problems associated with long running
proceses. Here's an article that shows how:

http://www.ftponline.com/vsm/2002_11/magazine/features/chester/defaul
t.aspx

or

http://tinyurl.com/ysaf7

Chris,

Pay careful attention to how the above article avoids the problems I
discussed. The extra threads don't use any page-based resources, and don't
care whether or not the initial page request is complete. Instead, they
reference data stored in Session.

Now, what happens in this example when the user hits Refresh? Does the
example wind up with two prime number threads?

All due respect, but this is not something which should be attempted by
anyone who does not consider himself an expert. And all due respect to
"Visual Studio Magazine", but nobody should ever put risky code into
production based on one of their articles. This kind of disjointed, fluffy
article is why I let my one and only subscription to that magazine lapse.
Among other faults, the article skims over teaching about synchronization,
and says nothing at all about what the extra thread can and cannot touch.
 
J

John Saunders

who be dat? said:
Hi Chris,

I'm writing a bulletinboard application in order to learn ASP.Net.

If you're trying to learn ASP.NET, you should dump your multithreading code
and try again. How many examples of multithreading in ASP.NET do you see on
the MSDN web site?

You have a great advantage as a beginner to ASP.NET: you can save yourself
a lifetime of grief by taking my advice and ignoring threads in ASP.NET
today!

Eventually, after several years of experience, you may find an ASP.NET
problem which you cannot solve without threads. That might be the time to
think about using threads again. But it's likely that it will _still_ be the
wrong way to go.
 
W

who be dat?

Yeah, I'm just going to forget this and just call the code everytime someone
responds versus use a seperate thread. I'm seeing headaches galore as I
work on this. Thanks everyone!!

Chris Smith
 
S

Scott Allen

All due respect, but this is not something which should be attempted by
anyone who does not consider himself an expert. And all due respect to
"Visual Studio Magazine", but nobody should ever put risky code into
production based on one of their articles. This kind of disjointed, fluffy
article is why I let my one and only subscription to that magazine lapse.
Among other faults, the article skims over teaching about synchronization,
and says nothing at all about what the extra thread can and cannot touch.

Agreed! Articles like this run a good chance of starting more problems
than it solves.

--s
 
J

Joe Fallon

I use Rick Strahl's SMTP class to send e-mails out asynchronously.
It works great.

The end user gets to continue navigating *immedialtely* while a
 

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

Members online

No members online now.

Forum statistics

Threads
473,989
Messages
2,570,207
Members
46,782
Latest member
ThomasGex

Latest Threads

Top