Threading - Is this Ok?

  • Thread starter richard.markiewicz
  • Start date
R

richard.markiewicz

Hi,

I'm developing a custom web part (basically an ASP web control in a
fancy wrapper if you're not familiar), something which I've done
several times before. However this one is a little different, as it
exists on a page and when the user presses a button, has to do a long
running operation. I want the page to still be interactive in this
time, with the web part showing status updates until it's finished.

So - I've implemented the Microsoft AJAX controls to allow me to
refresh just the web part when I need to update it. I can update the
panel using a Timer control. Now I need to do the actual work - and to
do that I believe the only way is to spin the work out into a separate
thread? I've never worked with threading before, and am anxious about
ending up thedailywtf.com. My requirements are very simple - just a
single thread to do the work in the background.

So - I was hoping someone with more experience might look over what
I've got and tell me if I'm on the right lines, or heading for a fall:

System.Web.UI.Timer myTimer = new System.Web.UI.Timer();
Thread threadObj;
private static string Status = "";

private void HandleButtonClick(object sender, EventArgs
eventArgs)
{
Page.Validate();
if (Page.IsValid)//Do some validation on the information
entered
{
myTimer.Enabled = true;
threadObj = new Thread(new
ThreadStart(LongRunningProcess));
threadObj.Start();
}
}

void myTimer_Tick(object sender, EventArgs e)
{
if ((Status == "Error") || (Status == "Finished"))
{
T.Enabled = false;
}
}

private void LongRunningProcess()
{
try
{
//Do some work that's going to take a while, call some
other classes/methods
Status = "Finished that bit of work";
//Do some work that's going to take a while, call some
other classes/methods
Status = "Finished";
}
catch (Exception ex)
{
Status = "Error";
}
}

Is it appropriate to use a thread in this scenario? Is it appropriate
for me set a "status" in my long running process, and then poll that
status using a timer every few seconds? Do I need to be doing anything
else with my thread when it's finished, or when it errors?

Many many thanks in advance, Richard
 
S

Sergey Zyuzin

Hi,

I'm developing a custom web part (basically an ASP web control in a
fancy wrapper if you're not familiar), something which I've done
several times before. However this one is a little different, as it
exists on a page and when the user presses a button, has to do a long
running operation. I want the page to still be interactive in this
time, with the web part showing status updates until it's finished.

So - I've implemented the Microsoft AJAX controls to allow me to
refresh just the web part when I need to update it. I can update the
panel using a Timer control. Now I need to do the actual work - and to
do that I believe the only way is to spin the work out into a separate
thread? I've never worked with threading before, and am anxious about
ending up thedailywtf.com. My requirements are very simple - just a
single thread to do the work in the background.

So - I was hoping someone with more experience might look over what
I've got and tell me if I'm on the right lines, or heading for a fall:

        System.Web.UI.Timer myTimer = new System.Web.UI.Timer();
        Thread threadObj;
        private static string Status = "";

        private void HandleButtonClick(object sender, EventArgs
eventArgs)
        {
            Page.Validate();
            if (Page.IsValid)//Do some validation on the information
entered
            {
                myTimer.Enabled = true;
                threadObj = new Thread(new
ThreadStart(LongRunningProcess));
                threadObj.Start();
            }
        }

        void myTimer_Tick(object sender, EventArgs e)
        {
            if ((Status == "Error") || (Status == "Finished"))
            {
                T.Enabled = false;
            }
        }

        private void LongRunningProcess()
        {
            try
            {
                //Do some work that's going to take a while, call some
other classes/methods
                Status = "Finished that bit of work";
                //Do some work that's going to take a while, call some
other classes/methods
                Status = "Finished";
            }
            catch (Exception ex)
            {
                Status = "Error";
            }
        }

Is it appropriate to use a thread in this scenario? Is it appropriate
for me set a "status" in my long running process, and then poll that
status using a timer every few seconds? Do I need to be doing anything
else with my thread when it's finished, or when it errors?

Many many thanks in advance, Richard

I'm not sure I understand how it's going to work. I didn't work with
Microsoft AJAX,
but the timer runs on server and it will fire when the page is already
sent to client. So client will not see any progress. I think there
should be a timer on the client side (in browser) which will cause
requests to server to refresh progress.

Also I wouldn't start a thread in page handler that is not going to
finish until request finishes. 100 clients can cause 100 threads
running simultaneously. I would rather create a queue somewhere (MSMQ,
SQL Server or smth). Page handler would put tasks in this queue and
some Windows Service would process them, periodically reporting
status.

HTH,
Sergey
 
R

richard.markiewicz

I'm not sure I understand how it's going to work. I didn't work with
Microsoft AJAX,
but the timer runs on server and it will fire when the page is already
sent to client. So client will not see any progress. I think there
should be a timer on the client side (in browser) which will cause
requests to server to refresh progress.

Also I wouldn't start a thread in page handler that is not going to
finish until request finishes. 100 clients can cause 100 threads
running simultaneously. I would rather create a queue somewhere (MSMQ,
SQL Server or smth). Page handler would put tasks in this queue and
some Windows Service would process them, periodically reporting
status.

HTH,
Sergey

Thanks Sergey.

The timer stuff basically works, because it's an AJAX update panel
that gets updated when the timer ticks - it's not the whole page
getting refreshed.

To simplify the problem, forgetting the AJAX stuff. Maybe this is more
of an ASP.NET question than a C# language question.

The control will be used by 1, maybe 2 users at a time. The long
running code takes maybe 10 seconds to execute (long enough that I
need to do something to keep the app responsive, or the user thinks it
has crashed). But let's be pessimistic and say I'll have 100
simultaneous users and the code takes 100 seconds to execute.

What are the disadvantages of 100 clients causing 100 threads to run
simultaneously? Is it just a performance thing? Or am I heading for a
crash? Is there a limit on the number of threads I can run
simultaneously?

If an exception occurs in my thread, do I need to do anything special,
any cleaning up after myself? Or when the thread finishes or hits an
unhandled exception, does it just shut down?

If one has a long running process going in a separate thread, and
needs to check the status of it every few seconds, or determine when
it's finished, what's the best way to do that? Is it appropriate for
me to poll a thread for a "status" value? Or is there some native way
to do this that I'm missing?

Many thanks again,

Richard
 
S

Sergey Zyuzin

Thanks Sergey.

The timer stuff basically works, because it's an AJAX update panel
that gets updated when the timer ticks - it's not the whole page
getting refreshed.

To simplify the problem, forgetting the AJAX stuff. Maybe this is more
of an ASP.NET question than a C# language question.

The control will be used by 1, maybe 2 users at a time. The long
running code takes maybe 10 seconds to execute (long enough that I
need to do something to keep the app responsive, or the user thinks it
has crashed). But let's be pessimistic and say I'll have 100
simultaneous users and the code takes 100 seconds to execute.

What are the disadvantages of 100 clients causing 100 threads to run
simultaneously? Is it just a performance thing? Or am I heading for a
crash? Is there a limit on the number of threads I can run
simultaneously?

If an exception occurs in my thread, do I need to do anything special,
any cleaning up after myself? Or when the thread finishes or hits an
unhandled exception, does it just shut down?

If one has a long running process going in a separate thread, and
needs to check the status of it every few seconds, or determine when
it's finished, what's the best way to do that? Is it appropriate for
me to poll a thread for a "status" value? Or is there some native way
to do this that I'm missing?

Many thanks again,

Richard- óËÒÙÔØ ÃÉÔÉÒÕÅÍÙÊ ÔÅËÓÔ-

- ðÏËÁÚÁÔØ ÃÉÔÉÒÕÅÍÙÊ ÔÅËÓÔ -

Hi, Richard,
I see now, System.Web.UI.Timer is a client timer (I've learned a bit
of Microsoft AJAX now :))

If you have lots of threads running long operations most likely your
server will be very busy serving them and
won't be able to process requests from other users quickly (however
that depends on what and how threads do).
Having 100 threads processing 100 tasks can appear to be slower than 2
threads processing the same 100 tasks consequently.
(But that's again depends). There's also some performance/memory
overhead on creating threads, so often a thread pool
is used instead.

I was talking about large scale applications, so if you have few
users, you don't have a web farm you can probably use threads inside
ASP.net process to execute long running task, as you do (also this
seems a little unusual to me. Maybe you'd better ask in ASP.NET
forums)

You need to handle exceptions in your threads, otherwise web server
process may crash.

For status you can not use that static variable. If you have 2 users
that will start two threads, then both threads will write to the same
variable.
I think you can put Status into Session state and pass Session to a
thread so it updates Status as needed (if you don't store Session in
database or another computer). When timer fires you can get Status
back from Session and send it back to user. Session is not thread-
safe, so you might need to lock when accessing it.

HTH,
Sergey
 
R

richard.markiewicz

Hi, Richard,
I see now, System.Web.UI.Timer is a client timer (I've learned a bit
of Microsoft AJAX now :))

If you have lots of threads running long operations most likely your
server will be very busy serving them and
won't be able to process requests from other users quickly (however
that depends on what and how threads do).
Having 100 threads processing 100 tasks can appear to be slower than 2
threads processing the same 100 tasks consequently.
(But that's again depends). There's also some performance/memory
overhead on creating threads, so often a thread pool
is used instead.

I was talking about large scale applications, so if you have few
users, you don't have a web farm you can probably use threads inside
ASP.net process to execute long running task, as you do (also this
seems a little unusual to me. Maybe you'd better ask in ASP.NET
forums)

You need to handle exceptions in your threads, otherwise web server
process may crash.

For status you can not use that static variable. If you have 2 users
that will start two threads, then both threads will write to the same
variable.
I think you can put Status into Session state and pass Session to a
thread so it updates Status as needed (if you don't store Session in
database or another computer). When timer fires you can get Status
back from Session and send it back to user. Session is not thread-
safe, so you might need to lock when accessing it.

HTH,
Sergey

Thank you Sergey.

Realistically I don't actually need to know the exact status of the
thread - and I won't communicate that to the user.

What I do need to know is when the thread has finished - so that I can
disable my timer and stop updating the page.

I guess I'm approaching this in completely the wrong way!

public class DoWork
{
public void LongRunningProcess()
{
try
{
// Long running code here

}
catch (Exception ex)
{
// Handle the error
}
}
}

public class My Control
{
DoWork doWork = new DoWork();
Thread threadObj;
System.Web.UI.Timer T = new System.Web.UI.Timer();

protected override void CreateChildControls()
{
try
{
threadObj = new Thread(new
ThreadStart(doWork.LongRunningProcess));
... snip...
}
catch (Exception ex)
{
LogError(ex);
}
}

void T_Tick(object sender, EventArgs e)
{
// Want to check the threadstate here, but it never
changes? Although the thread is runs successfully, when I check
threadObj.ThreadState it is always "Not started".
}

private void HandleButtonClick(object sender, EventArgs
eventArgs)
{
btStart.Enabled = false;
threadObj.Start();
T.Enabled = true;
}
}

What would be the best way to approach this? It seems like it should
be fairly easy. The code in T_Tick executes every time the timer ticks
so why can't it see the state of my thread?

Many thanks in advance, R
 
S

Sergey Zyuzin

Thank you Sergey.

Realistically I don't actually need to know the exact status of the
thread - and I won't communicate that to the user.

What I do need to know is when the thread has finished - so that I can
disable my timer and stop updating the page.

I guess I'm approaching this in completely the wrong way!

    public class DoWork
    {
        public void LongRunningProcess()
        {
            try
            {
               // Long running code here

            }
            catch (Exception ex)
            {
                // Handle the error
            }
        }
    }

    public class My Control
    {
        DoWork doWork = new DoWork();
        Thread threadObj;
        System.Web.UI.Timer T = new System.Web.UI.Timer();

        protected override void CreateChildControls()
        {
            try
            {
                threadObj = new Thread(new
ThreadStart(doWork.LongRunningProcess));
                ... snip...
            }
            catch (Exception ex)
            {
                LogError(ex);
            }
        }

        void T_Tick(object sender, EventArgs e)
        {
            // Want to check the threadstate here, but it never
changes? Although the thread is runs successfully, when I check
threadObj.ThreadState it is always "Not started".
        }

        private void HandleButtonClick(object sender, EventArgs
eventArgs)
        {
                btStart.Enabled = false;
                threadObj.Start();
                T.Enabled = true;
        }
    }

What would be the best way to approach this? It seems like it should
be fairly easy. The code in T_Tick executes every time the timer ticks
so why can't it see the state of my thread?

Many thanks in advance, R- Hide quoted text -

- Show quoted text -


Every time timer fires on client it makes request to server.
When server handles request it creates new Page object and Controls
that the page contains.
So, on each timer tick you create new Thread object in
CreateChildControls and its status is "Not Started" because Start
method of this instance of thread was not called.
The thread that you've started when user clicked the button is
running, but you've lost reference to it.

If you want to implement it with threads the simplest would be to
store reference to thread in Session state when you start the thread
and retrieve it from Session state when timer ticks to get its
status(and remove the thread from Session right before thread
finishes).

Maybe someone in ASP.Net groups could provide you with sample code or
tell about some patterns you can use to solve your task - I've never
used this approach.

If you need I can try to implement it later.

Thanks,
Sergey
 
S

Sergey Zyuzin

Thank you Sergey.

Realistically I don't actually need to know the exact status of the
thread - and I won't communicate that to the user.

What I do need to know is when the thread has finished - so that I can
disable my timer and stop updating the page.

I guess I'm approaching this in completely the wrong way!

    public class DoWork
    {
        public void LongRunningProcess()
        {
            try
            {
               // Long running code here

            }
            catch (Exception ex)
            {
                // Handle the error
            }
        }
    }

    public class My Control
    {
        DoWork doWork = new DoWork();
        Thread threadObj;
        System.Web.UI.Timer T = new System.Web.UI.Timer();

        protected override void CreateChildControls()
        {
            try
            {
                threadObj = new Thread(new
ThreadStart(doWork.LongRunningProcess));
                ... snip...
            }
            catch (Exception ex)
            {
                LogError(ex);
            }
        }

        void T_Tick(object sender, EventArgs e)
        {
            // Want to check the threadstatehere, but it never
changes? Although the thread is runs successfully, when I check
threadObj.ThreadState it is always "Not started".
        }

        private void HandleButtonClick(object sender, EventArgs
eventArgs)
        {
                btStart.Enabled = false;
                threadObj.Start();
                T.Enabled = true;
        }
    }

What would be the best way to approach this? It seems like it should
be fairly easy. The code in T_Tick executes every time the timer ticks
so why can't it see the state of my thread?

Many thanks in advance, R- Скрыть цитируемый текÑÑ‚ -

- Показать цитируемый текÑÑ‚ -

By the way, if you don't need to report exact status, maybe you just
execute your long running task synchronously and
include UpdateProgress control so user can see progress of loading
UpdatePanel (I don't know how it looks - just read about it)? As soon
as you have only a couple of users this can work.
 
R

richard.markiewicz

Every time timer fires on client it makes request to server.
When server handles request it creates new Page object and Controls
that the page contains.
So, on each timer tick you create new Thread object in
CreateChildControls and its status is "Not Started" because Start
method of this instance of thread was not called.
The thread that you've started when user clicked the button is
running, but you've lost reference to it.

If you want to implement it with threads the simplest would be to
store reference to thread in Session state when you start the thread
and retrieve it from Session state when timer ticks to get its
status(and remove the thread from Session right before thread
finishes).

Maybe someone in ASP.Net groups could provide you with sample code or
tell about some patterns you can use to solve your task - I've never
used this approach.

If you need I can try to implement it later.

Thanks,
Sergey

Hi Sergey, thanks again

I see exactly what you are saying about the page lifecycle. To be
honest I hadn't researched it properly, and had assumed that because
my work was being done in an updatepanel, it wasn't participating in
the usual way.

I did try and implement the approach that you suggested - both using
session state and view state - but I had problems with the
implementation; I think this was related to serializing the object.

Given how difficult it was proving to implement (annoyingly - the part
which should've been easy turned out to be the hard part) and worried
that I was heading for another holdup, I've gone back to the drawing
board slightly. I sat down and read a fair chunk of the documentation
on ASP.NET AJAX and have now taken a different approach.

While it is not really a c# language thing - in case you are
interested: basically I've dropped the idea of using a timer and a
thread, pulled them both from the project. I have implemented another
ASP.NET AJAX control - the updateprogress. My button now fires the
long running code directly from it's click handler - and while the
panel is waiting to update, the updateprogress kicks in and allows me
to drop a <div> on top of the control. This displays my "loading"
message for as long as the updatepanel is refreshing (i.e. until my
long running code finishes), and then when the panel is ready to
refresh it disappears again.

Sometimes you just can't see the wood for the trees! Anyway, I'm very
grateful for your help and have learned a lot about threading in the
last couple of days that is sure to be useful. So the time spent
certainly wasn't wasted at least.

Thanks again, R
 
R

richard.markiewicz

By the way, if you don't need to ...

read more »

Huh - great minds think alike? Your post wasn't showing in Groups when
I wrote mine!

Thanks again

R
 

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

Similar Threads


Top