A
Alphapage
Hello,
You can find my AsyncPage class which inherits from Page and
IHttpAsyncHandler.
I inherit my default.aspx page from AsyncPage and put a linkbutton on that
page and set the PostbackUrl property to
http://localhost:port/default.aspx?test=1
I run my app, the page is displayed (no problem), I click the linkbutton
(the page sleeps during 20000ms, no problem).
The problem is if I open second tab in Internet Explorer or Firefox and go
to http://localhost:port/default.aspx when the first is still sleeping, the
second tab freezes.
It seems the Asp.Net ThreadPool thread used by the first tab is locked and
not sent back to the Asp.Net ThreadPool as it should be. So, the second tab
is pushed in the queue of this strange waiting thread and freezes until the
first tab finished sleeping.
How can I bypass this trouble ? (ie: I know all about Asynchrounous pages in
Asp.Net 2.0, but I want to implement my own threadpool)
My code seems good and is an example of:
http://msdn.microsoft.com/msdnmag/issues/03/06/Threading/default.aspx
Here is my AsyncPage class:
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Threading;
namespace WebApplicationThreadPool
{
public class AsyncPage3: Page,IHttpAsyncHandler
{
static protected DevelopMentor.ThreadPool _threadPool;
static AsyncPage3()
{
_threadPool =
new DevelopMentor.ThreadPool(2, 25, "AsyncPool");
_threadPool.PropogateCallContext = true;
_threadPool.PropogateThreadPrincipal = true;
_threadPool.PropogateHttpContext = true;
_threadPool.Start();
}
public new void ProcessRequest(HttpContext ctx)
{
// not used
}
public new bool IsReusable
{
get { return false; }
}
#region IHttpAsyncHandler Members
public IAsyncResult BeginProcessRequest(HttpContext context,
AsyncCallback cb, object extraData)
{
context.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest called
on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
AsyncRequestState reqState =
new AsyncRequestState(context, cb, extraData);
_threadPool.PostRequest(
new DevelopMentor.WorkRequestDelegate(ProcessRequest),
reqState);
context.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest called
on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
return reqState;
}
public void EndProcessRequest(IAsyncResult result)
{
AsyncRequestState reqState = (AsyncRequestState)result;
reqState.ctx.Response.Output.Write("IHttpAsyncHandler.EndProcessRequest
called on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
}
#endregion
void ProcessRequest(object state, DateTime requestTime)
{
AsyncRequestState reqState = state as AsyncRequestState;
if (reqState.ctx.Request.QueryString["test"]=="1")
Thread.Sleep(20000);
// Synchronously call base class Page.ProcessRequest
// as you are now on a thread pool thread.
base.ProcessRequest(reqState.ctx);
reqState.ctx.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest
called on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
//Thread.Sleep(20000);
// This triggers the asp.net plumbing to call our
// IHttpAsyncHandler.EndProcessRequest method.
//
reqState.CompleteRequest();
reqState.cb(reqState);
}
public class AsyncRequestState : IAsyncResult
{
public AsyncRequestState(HttpContext ctx, AsyncCallback cb,
object extraData)
{
this.ctx = ctx;
this.cb = cb;
this.extraData = extraData;
}
internal HttpContext ctx;
internal AsyncCallback cb;
internal object extraData;
private bool isCompleted = false;
private ManualResetEvent callCompleteEvent = null;
internal void CompleteRequest()
{
isCompleted = true;
lock (this)
{
if (callCompleteEvent != null)
{
callCompleteEvent.Set();
}
}
}
// IAsyncResult
//
public object AsyncState { get { return (extraData); } }
public bool CompletedSynchronously { get { return (false); } }
public bool IsCompleted { get { return (isCompleted); } }
public WaitHandle AsyncWaitHandle
{
get
{
lock (this)
{
if (callCompleteEvent == null)
{
callCompleteEvent = new ManualResetEvent(false);
}
return (callCompleteEvent);
}
}
}
}
}
}
Thanks in advance for your help.
You can find my AsyncPage class which inherits from Page and
IHttpAsyncHandler.
I inherit my default.aspx page from AsyncPage and put a linkbutton on that
page and set the PostbackUrl property to
http://localhost:port/default.aspx?test=1
I run my app, the page is displayed (no problem), I click the linkbutton
(the page sleeps during 20000ms, no problem).
The problem is if I open second tab in Internet Explorer or Firefox and go
to http://localhost:port/default.aspx when the first is still sleeping, the
second tab freezes.
It seems the Asp.Net ThreadPool thread used by the first tab is locked and
not sent back to the Asp.Net ThreadPool as it should be. So, the second tab
is pushed in the queue of this strange waiting thread and freezes until the
first tab finished sleeping.
How can I bypass this trouble ? (ie: I know all about Asynchrounous pages in
Asp.Net 2.0, but I want to implement my own threadpool)
My code seems good and is an example of:
http://msdn.microsoft.com/msdnmag/issues/03/06/Threading/default.aspx
Here is my AsyncPage class:
using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Threading;
namespace WebApplicationThreadPool
{
public class AsyncPage3: Page,IHttpAsyncHandler
{
static protected DevelopMentor.ThreadPool _threadPool;
static AsyncPage3()
{
_threadPool =
new DevelopMentor.ThreadPool(2, 25, "AsyncPool");
_threadPool.PropogateCallContext = true;
_threadPool.PropogateThreadPrincipal = true;
_threadPool.PropogateHttpContext = true;
_threadPool.Start();
}
public new void ProcessRequest(HttpContext ctx)
{
// not used
}
public new bool IsReusable
{
get { return false; }
}
#region IHttpAsyncHandler Members
public IAsyncResult BeginProcessRequest(HttpContext context,
AsyncCallback cb, object extraData)
{
context.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest called
on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
AsyncRequestState reqState =
new AsyncRequestState(context, cb, extraData);
_threadPool.PostRequest(
new DevelopMentor.WorkRequestDelegate(ProcessRequest),
reqState);
context.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest called
on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
return reqState;
}
public void EndProcessRequest(IAsyncResult result)
{
AsyncRequestState reqState = (AsyncRequestState)result;
reqState.ctx.Response.Output.Write("IHttpAsyncHandler.EndProcessRequest
called on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
}
#endregion
void ProcessRequest(object state, DateTime requestTime)
{
AsyncRequestState reqState = state as AsyncRequestState;
if (reqState.ctx.Request.QueryString["test"]=="1")
Thread.Sleep(20000);
// Synchronously call base class Page.ProcessRequest
// as you are now on a thread pool thread.
base.ProcessRequest(reqState.ctx);
reqState.ctx.Response.Output.Write("IHttpAsyncHandler.BeginProcessRequest
called on thread {0}<br/>",
AppDomain.GetCurrentThreadId());
//Thread.Sleep(20000);
// This triggers the asp.net plumbing to call our
// IHttpAsyncHandler.EndProcessRequest method.
//
reqState.CompleteRequest();
reqState.cb(reqState);
}
public class AsyncRequestState : IAsyncResult
{
public AsyncRequestState(HttpContext ctx, AsyncCallback cb,
object extraData)
{
this.ctx = ctx;
this.cb = cb;
this.extraData = extraData;
}
internal HttpContext ctx;
internal AsyncCallback cb;
internal object extraData;
private bool isCompleted = false;
private ManualResetEvent callCompleteEvent = null;
internal void CompleteRequest()
{
isCompleted = true;
lock (this)
{
if (callCompleteEvent != null)
{
callCompleteEvent.Set();
}
}
}
// IAsyncResult
//
public object AsyncState { get { return (extraData); } }
public bool CompletedSynchronously { get { return (false); } }
public bool IsCompleted { get { return (isCompleted); } }
public WaitHandle AsyncWaitHandle
{
get
{
lock (this)
{
if (callCompleteEvent == null)
{
callCompleteEvent = new ManualResetEvent(false);
}
return (callCompleteEvent);
}
}
}
}
}
}
Thanks in advance for your help.