unrelated event killing an asynchronous thread in progress

J

James Irvine

I posted this to an ASP.Net group awhile ago, but nobody responded, so
maybe this more in the C# realm. Anyway, I launch an asynchronous
thread by clicking ButtonInitAsyncThread, which works fine. When it's
done, it sends back it's results.

But, while this thread is still running, if I click on
ButtonCheckThreadStatus, which has nothing to do with the async thread
running, it cancels the thread, and the thread never sends back the
results. What causes this?

thanks -James



The complete C# code-behind:


using System;
using System.Threading;

public partial class testThreads : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}

public delegate long SampSyncSqrDelegate(long i);

protected void ButtonInitAsyncThread_Click(object sender, EventArgs
e) // async call
{
long inParm = Convert.ToInt32(TextBoxInParm.Text);
long callResult = -1;

WorkerClass sampSyncObj = new WorkerClass();


// launch longWindedMethod method Asynchronously:
SampSyncSqrDelegate sampleDelegate = new
SampSyncSqrDelegate(sampSyncObj.longWindedMethod);

IAsyncResult aResult = sampleDelegate.BeginInvoke(inParm, null,
null);

//Wait for the call to complete
aResult.AsyncWaitHandle.WaitOne();

// get the output returned back:
callResult = sampleDelegate.EndInvoke(aResult);
LabelThreadStatus.Text = Convert.ToString(callResult);
}

protected void ButtonCheckThreadStatus_Click(object sender,
EventArgs e)
{
Label1.Text = Convert.ToString(DateTime.Now);
}
}

public class WorkerClass
{
// A method that does some time-consuming work - returns the number
passed in + 'a':
public long longWindedMethod(long longIn)
{
int a = 0;

while (a < 5)
{
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine(a);
a++;
}
return a + longIn;
}
}






And the complete aspx listing:

<%@ Page Language="C#" MasterPageFile="~/MasterPageGold.master"
AutoEventWireup="true" CodeFile="why.aspx.cs" Inherits="testThreads"
Title="Untitled Page" %>
<asp:Content ID="Content1"
ContentPlaceHolderID="ContentPlaceHolderForBody" Runat="Server">
<br />
<asp:Button ID="ButtonInitAsyncThread" runat="server" Text="init
async thread" OnClick="ButtonInitAsyncThread_Click" />&nbsp;
<asp:TextBox ID="TextBoxInParm" runat="server">78</asp:TextBox>
<asp:Label ID="LabelThreadStatus" runat="server" Text="thread
status"></asp:Label><br />
<br />
<br />
<asp:Button ID="ButtonCheckThreadStatus" runat="server"
Text="CheckThreadStatus" OnClick="ButtonCheckThreadStatus_Click" />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</asp:Content>
 
P

Peter Duniho

I posted this to an ASP.Net group awhile ago, but nobody responded, so
maybe this more in the C# realm. Anyway, I launch an asynchronous
thread by clicking ButtonInitAsyncThread, which works fine. When it's
done, it sends back it's results.

But, while this thread is still running, if I click on
ButtonCheckThreadStatus, which has nothing to do with the async thread
running, it cancels the thread, and the thread never sends back the
results. What causes this?

Actually, I think this may well have at least a little to do with it being
ASP.NET versus C#.

In a plain Form application, doing what you're doing here would result in
an inoperable UI. Because you wait in the click handler until the long
process is done, nothing else in the form can be handled. The user
wouldn't be able to click on the status button in the first place, nor do
anything else with the UI.

So presumably, at least some aspect of the problem is due to the web-based
environment in which your code is operating.

What exactly is going on, I can't say. I don't know anything about
ASP.NET. You should verify what exactly is happening though. It seems
odd to me that clicking on a button in the browser (I assume that's where
the UI is shown) would cause the thread in your click handler to be
aborted. So the first thing to do is put in some logging or something so
that you can tell whether the thread really has stopped, or if it's just
somehow been disconnected from the UI.

I suspect it's the latter, but what the solution for that might be I don't
know.

What I can tell you is that it doesn't make much sense to me for code to
start a new thread to run some processing, and then to simply sit and wait
for that thread to finish. The processing might as well just be done on
the same thread if you're going to do that.

Pete
 
J

James Irvine

Peter said:
Actually, I think this may well have at least a little to do with it
being ASP.NET versus C#.

In a plain Form application, doing what you're doing here would result
in an inoperable UI. Because you wait in the click handler until the
long process is done, nothing else in the form can be handled. The user
wouldn't be able to click on the status button in the first place, nor
do anything else with the UI.

So presumably, at least some aspect of the problem is due to the
web-based environment in which your code is operating.

What exactly is going on, I can't say. I don't know anything about
ASP.NET. You should verify what exactly is happening though. It seems
odd to me that clicking on a button in the browser (I assume that's
where the UI is shown) would cause the thread in your click handler to
be aborted. So the first thing to do is put in some logging or
something so that you can tell whether the thread really has stopped, or
if it's just somehow been disconnected from the UI.

I suspect it's the latter, but what the solution for that might be I
don't know.

What I can tell you is that it doesn't make much sense to me for code to
start a new thread to run some processing, and then to simply sit and
wait for that thread to finish. The processing might as well just be
done on the same thread if you're going to do that.

Pete

I rewrote it as a Forms app, and my error became clear. Thanks for pointing out the defect! -James


This does what I was aiming for (moving the results harvesting to another event fixed it). Now while the background
thread is running I can click away on other buttons:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplicationAsyncButtons
{
public partial class Form1 : Form
{
// Async delegate used to call a method with this signature asynchronously
public delegate long SampSyncSqrDelegate(long i);
public IAsyncResult aResult;
public SampSyncSqrDelegate sampleDelegate;


public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
long inParm = Convert.ToInt32(TextBoxInParm.Text);

WorkerClass sampSyncObj = new WorkerClass();


// launch longWindedMethod method Asynchronously:
sampleDelegate = new SampSyncSqrDelegate(sampSyncObj.longWindedMethod);

aResult = sampleDelegate.BeginInvoke(inParm, null, null);

// *** Don't *** wait here for the call to complete
//aResult.AsyncWaitHandle.WaitOne();

// get the output returned back:
//callResult = sampleDelegate.EndInvoke(aResult);
//LabelThreadStatus.Text = Convert.ToString(callResult);
}

private void button2_Click(object sender, EventArgs e)
{
label2.Text = Convert.ToString(DateTime.Now);
}

private void buttonGetResults_Click(object sender, EventArgs e)
{
long callResult = -1;

// get the output returned back:
callResult = sampleDelegate.EndInvoke(aResult);
LabelThreadStatus.Text = Convert.ToString(callResult);
}


}

public class WorkerClass
{
// A method that does some time-consuming work - returns the number passed in + 'a':
public long longWindedMethod(long longIn)
{
int a = 0;

while (a < 5)
{
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine(a);
a++;
}
return a + longIn;
}
}

}
 
P

Peter Duniho

I rewrote it as a Forms app, and my error became clear. Thanks for
pointing out the defect! -James

This does what I was aiming for (moving the results harvesting to
another event fixed it). Now while the background thread is running I
can click away on other buttons:

Hmmm...I think you're almost there. :)

In particular, I'm pretty sure that calling EndInvoke() on the delegate
will block until the delegate has returned. This means you've simply
moved the blocking behavior from the click handler for the start button to
the click handler for the "get results" button. If you click that button
before the delegate is done, you have the same problem.

Better would be to use a callback or event for the long process delegate
to use, so that you are notified when it finishes, rather than relying on
the user to not get the results until after it's done.

Pete
 
J

James Irvine

Peter said:
Hmmm...I think you're almost there. :)

In particular, I'm pretty sure that calling EndInvoke() on the delegate
will block until the delegate has returned. This means you've simply
moved the blocking behavior from the click handler for the start button
to the click handler for the "get results" button. If you click that
button before the delegate is done, you have the same problem.

Better would be to use a callback or event for the long process delegate
to use, so that you are notified when it finishes, rather than relying
on the user to not get the results until after it's done.

Pete

Way better. In fact, awesome! thanks for the lesson -James


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplicationAsyncButtons
{
public partial class Form1 : Form
{
// Async delegate used to call a method with this signature asynchronously
public delegate long SampSyncSqrDelegate(long i);
public IAsyncResult aResult;
public SampSyncSqrDelegate sampleDelegate;


public Form1()
{
InitializeComponent();
}

private void button1_Click(object sender, EventArgs e)
{
long inParm = Convert.ToInt32(TextBoxInParm.Text);

WorkerClass sampSyncObj = new WorkerClass();


// launch longWindedMethod method Asynchronously:
sampleDelegate = new SampSyncSqrDelegate(sampSyncObj.longWindedMethod);

aResult = sampleDelegate.BeginInvoke(inParm, OnAsyncCallBack, null);
//del.BeginInvoke(az, bz, OnAsyncCallBack, null);


//Wait for the call to complete
//aResult.AsyncWaitHandle.WaitOne();

// get the output returned back:
//callResult = sampleDelegate.EndInvoke(aResult);
//LabelThreadStatus.Text = Convert.ToString(callResult);
}

private void button2_Click(object sender, EventArgs e)
{
label2.Text = Convert.ToString(DateTime.Now);
}

void OnAsyncCallBack(IAsyncResult asyncResult) // goes here on callback
{
// get the output returned back:
long callResult = sampleDelegate.EndInvoke(aResult);
LabelThreadStatus.Text = Convert.ToString(callResult);
}

}

public class WorkerClass
{
// A method that does some time-consuming work - returns the number passed in + 'a':
public long longWindedMethod(long longIn)
{
int a = 0;

while (a < 5)
{
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine(a);
a++;
}
return a + longIn;
}
}

}
 
J

James Irvine

Peter said:
Actually, I think this may well have at least a little to do with it
being ASP.NET versus C#.

In a plain Form application, doing what you're doing here would result
in an inoperable UI. Because you wait in the click handler until the
long process is done, nothing else in the form can be handled. The user
wouldn't be able to click on the status button in the first place, nor
do anything else with the UI.

So presumably, at least some aspect of the problem is due to the
web-based environment in which your code is operating.

What exactly is going on, I can't say. I don't know anything about
ASP.NET. You should verify what exactly is happening though. It seems
odd to me that clicking on a button in the browser (I assume that's
where the UI is shown) would cause the thread in your click handler to
be aborted.
........
So the first thing to do is put in some logging or
something so that you can tell whether the thread really has stopped, or
if it's just somehow been disconnected from the UI.


Just out of curiosity, I put in some file writing code and a sleeper in the background thread, ran the webpage, and then closed the page before the background
thread had finished, just to see if it would continue writing files even after it's head was cut off. It does.
 

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