Thread question

  • Thread starter Thread starter Alvin Bruney [MVP]
  • Start date Start date
A

Alvin Bruney [MVP]

Child threads aren't allowed to touch main thread objects. The session
object in ASP.NET belongs to the main thread. The way around this is to pass
in a reference in the thread constructor so that the child thread can use
the object safely since there is no control.invoke available like in
winforms.

Why does this work? This has been bugging for a while.

So the class would look something like this:

public class test
{
public test(HttpContext currObject);.....

and the call would be test t = new (HttpContext.Current);

Technically, I can't see what is happening behind the scenes to force thread
safety. Anybody?
 
Alvin,
Child threads aren't allowed to touch main thread objects.

While that's true for object with thread affinity (such as Winforms),
it's not always the case. Objects generally don't "belong" to any
single thread, you're allowed to use them from any thread as long as
you make sure everything is synchronized as needed.

The way around this is to pass
in a reference in the thread constructor so that the child thread can use
the object safely since there is no control.invoke available like in
winforms.

Why does this work?

I don't know much about ASP.NET, but I'd claim that it doesn't work.
There's no such thing as a thread constructor, you're just passing the
HttpContext to the constructor of the object which happend to contain
the thread code. There's nothing magic in that operation that makes an
object thread safe if it wasn't before.



Mattias
 
single thread, you're allowed to use them from any thread as long as
you make sure everything is synchronized as needed.

no. that's not correct.
You get an exception if you touch the intrinsic session object with a child
thread everytime. That goes for intrinsic objects as well as server controls
on the webform.

However, if you pass in a reference thru the thread constructor, this
approach never fails.
There's no such thing as a thread constructor, you're just passing the
HttpContext to the constructor of the object which happend to contain
the thread code.
right. I used the above for explanation purposes.

I understand that the architecture for webforms is completely different from
winforms inspite of the fact that they bear some superficial similarity in
form and function. I am yet to find a book or resource which covers
threading architecture of webforms and I have been searching for a couple
months. Frequently, attempting to answer webforms thread architecture based
on winforms scenarios ends up being completely wrong.
 
no. that's not correct.
You get an exception if you touch the intrinsic session object with a child
thread everytime. That goes for intrinsic objects as well as server controls
on the webform.

No, Mattias was correct. He said that objects don't *generally* belong
to one thread, and he was correct. If session objects are different,
that's a special case (like WinForms stuff). It doesn't change the
general case though.
However, if you pass in a reference thru the thread constructor, this
approach never fails.

Again, what do you mean by "thru the thread constructor"?
right. I used the above for explanation purposes.

I'm afraid it didn't explain a lot... could you try again?
 
trying again...
No, Mattias was correct. He said that objects don't *generally* belong
to one thread, and he was correct.

No, you both are wrong. The main thread of control which initializes an
application owns the form and the controls on the form. It is the main
thread but it's still a thread. It *owns the forms and controls (windows
controls or otherwise) because it is the only sequential stream of execution
which can interact with these components in a safe manner. All other
interactions by lesser threads will cause an exception - depending on
architecture. Consistence of these exceptions is entirely dependent on the
underlying operating system architecture - NT behaves differently from
non-NT systems.

This is why GUI operations to these controls must be executed by the thread
which owns these objects. That's not specific to webforms. You must
control.invoke to carry out the operation in a thread safe manner. For
webforms, there is no control.invoke. So how is it to be done? Well thru
trial and error, I've found that a reference must be passed in using the
code below. I'd like to know why this works since technically it really
should not.
Again, what do you mean by "thru the thread constructor"?
//consider a class which will be called from a thread
class t
{
httpcontext _val;
int _bogus = 0;
public t(httpcontext val,int bogus)
{
_val = val;
_bogus = bogus;
}
}

is what i meant.
 
I just tried this and it worked:

Protected WithEvents Butt As Button
Protected Txt As TextBox
Public M As MyObj

Public Class MyObj
Public MyStr As String
End Class

Private Sub Clk_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Handles Butt.Click
M = New MyObj
M.MyStr = "Testing"
Dim T As Threading.Thread = New Threading.Thread(AddressOf StartHere)
T.Start()
T.Join()
End Sub

Public Sub StartHere()
Txt.Text = M.MyStr
End Sub

Alvin Bruney said:
trying again...
No, Mattias was correct. He said that objects don't *generally* belong
to one thread, and he was correct.

No, you both are wrong. The main thread of control which initializes an
application owns the form and the controls on the form. It is the main
thread but it's still a thread. It *owns the forms and controls (windows
controls or otherwise) because it is the only sequential stream of execution
which can interact with these components in a safe manner. All other
interactions by lesser threads will cause an exception - depending on
architecture. Consistence of these exceptions is entirely dependent on the
underlying operating system architecture - NT behaves differently from
non-NT systems.

This is why GUI operations to these controls must be executed by the thread
which owns these objects. That's not specific to webforms. You must
control.invoke to carry out the operation in a thread safe manner. For
webforms, there is no control.invoke. So how is it to be done? Well thru
trial and error, I've found that a reference must be passed in using the
code below. I'd like to know why this works since technically it really
should not.
Again, what do you mean by "thru the thread constructor"?
//consider a class which will be called from a thread
class t
{
httpcontext _val;
int _bogus = 0;
public t(httpcontext val,int bogus)
{
_val = val;
_bogus = bogus;
}
}

is what i meant.
 
trying again...


No, you both are wrong. The main thread of control which initializes an
application owns the form and the controls on the form. It is the main
thread but it's still a thread. It *owns the forms and controls (windows
controls or otherwise) because it is the only sequential stream of execution
which can interact with these components in a safe manner. All other
interactions by lesser threads will cause an exception - depending on
architecture. Consistence of these exceptions is entirely dependent on the
underlying operating system architecture - NT behaves differently from
non-NT systems.

Sorry, that's still talking about *specific* objects - namely UI
objects. Mattias and I were talking in more *general* terms. Although
specific classes (even a wide variety of them) may have thread
affinity, it certainly isn't true that *all* do.
This is why GUI operations to these controls must be executed by the thread
which owns these objects. That's not specific to webforms.

No, it's specific to WinForms instead.
You must
control.invoke to carry out the operation in a thread safe manner. For
webforms, there is no control.invoke. So how is it to be done? Well thru
trial and error, I've found that a reference must be passed in using the
code below. I'd like to know why this works since technically it really
should not.

It seems rather unlikely that just passing the context through a
constructor makes any difference to it. Could you give two bits of
code, one which doesn't go through a constructor and one which does, to
illustrate the difference? Are you saying that if you access the
context after it's gone "through" a constructor, you've got thread-safe
access to it, but otherwise it always throws an exception? That really
does sound highly unlikely.
 
JD said:
I just tried this and it worked:

You haven't shown any imports - are you talking about Windows Forms or
web forms?
Protected WithEvents Butt As Button
Protected Txt As TextBox
Public M As MyObj

Public Class MyObj
Public MyStr As String
End Class

Private Sub Clk_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Handles Butt.Click
M = New MyObj
M.MyStr = "Testing"
Dim T As Threading.Thread = New Threading.Thread(AddressOf StartHere)
T.Start()
T.Join()
End Sub

Public Sub StartHere()
Txt.Text = M.MyStr
End Sub

Yes, it will sometimes work. It won't always though, and you
*certainly* shouldn't rely on it working.
 
ASP.NET.


Jon Skeet said:
You haven't shown any imports - are you talking about Windows Forms or
web forms?


Yes, it will sometimes work. It won't always though, and you
*certainly* shouldn't rely on it working.
 
JD said:

Right.

Now, is there any guarantee that the thread executing Clk_Click will
see the new value of Txt.Text? It depends on how the Text property is
implemented - but unless it's been written explicitly for that kind of
threading operation, it's not thread-safe - even if it happened to work
for you.
 
Mainly I was responding to Alvin's comment "You get an exception if you
touch the intrinsic session object with a child thread everytime. That goes
for intrinsic objects as well as server controls on the webform.".

Yes the Clk_Click thread does see the new value. I don't see any guarantee
that its thread safe but again it was only an example in response and I
wouldn't use it in production.

As for the HttpContext, the child thread has no HttpContext. HttpContext is
created on and associated with the request thread coming in. If the child
thread has a reference to the current context, it can access it without
throwing an exception, see below. I guess I'm trying to recreate what Alvin
is saying and cannot in my examples.

Protected WithEvents Butt As Button
Protected Txt As TextBox
Protected LBL As Label
Protected H As HttpContext

<Serializable()> Public Class MyObj
Public MyStr As String
End Class

Private Sub Clk_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Handles Butt.Click
Dim M As MyObj = New MyObj
M.MyStr = "Testing"
Session("M") = M
H = HttpContext.Current
Dim T As Threading.Thread = New Threading.Thread(AddressOf StartHere)
T.Start()
T.Join()
LBL.Text = Txt.Text
End Sub

Public Sub StartHere()
Txt.Text = CType(H.Session("M"), MyObj).MyStr
End Sub
 
Mattias and I were talking in more *general* terms
ok
It seems rather unlikely that just passing the context through a
constructor makes any difference to it. Could you give two bits of
code, one which doesn't go through a constructor and one which does, to
illustrate the difference?
I've been trying to produce this for a while and cannot get it to fail.

Are you saying that if you access the
context after it's gone "through" a constructor, you've got thread-safe
access to it, but otherwise it always throws an exception? That really
does sound highly unlikely.
I thought you hit upon something with this statement but I haven't been able
to confirm it with a test case for the longest while. I suspect it is the
meat of the issue but I am not able to demonstrate my theory effectively to
post anything.

What i am looking for, and am not able to produce yet, is an exception with
the following text
The type System.Web.HttpException
in Assembly System.Web, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is not
marked as serializable

I'm trying to test the theory that the object is already gone which causes
access to fail, but I am not successfull. I can still access the object for
some time after the page is thru executing and i don't get the exception i
am looking for.
 
JD said:
Mainly I was responding to Alvin's comment "You get an exception if you
touch the intrinsic session object with a child thread everytime. That goes
for intrinsic objects as well as server controls on the webform.".

Ah, right - fair enough. Sorry for the confusion.
 
i believe my comments were qualified to say that it may or may not happen
depending on underlying OS.

I can't reproduce it either, at least for now. I know I am not insane
because I've found a couple of threads on the newsgroups which produced this
exception.

--
Regards,
Alvin Bruney
[ASP.NET MVP http://mvp.support.microsoft.com/default.aspx]
Got tidbits? Get it here... http://tinyurl.com/27cok
JD said:
Mainly I was responding to Alvin's comment "You get an exception if you
touch the intrinsic session object with a child thread everytime. That
goes
for intrinsic objects as well as server controls on the webform.".

Yes the Clk_Click thread does see the new value. I don't see any
guarantee
that its thread safe but again it was only an example in response and I
wouldn't use it in production.

As for the HttpContext, the child thread has no HttpContext. HttpContext
is
created on and associated with the request thread coming in. If the child
thread has a reference to the current context, it can access it without
throwing an exception, see below. I guess I'm trying to recreate what
Alvin
is saying and cannot in my examples.

Protected WithEvents Butt As Button
Protected Txt As TextBox
Protected LBL As Label
Protected H As HttpContext

<Serializable()> Public Class MyObj
Public MyStr As String
End Class

Private Sub Clk_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Handles Butt.Click
Dim M As MyObj = New MyObj
M.MyStr = "Testing"
Session("M") = M
H = HttpContext.Current
Dim T As Threading.Thread = New Threading.Thread(AddressOf StartHere)
T.Start()
T.Join()
LBL.Text = Txt.Text
End Sub

Public Sub StartHere()
Txt.Text = CType(H.Session("M"), MyObj).MyStr
End Sub
 
i believe my comments were qualified to say that it may or may not happen
depending on underlying OS.

I can't reproduce it either, at least for now. I know I am not insane
because I've found a couple of threads on the newsgroups which produced this
exception.

What's the message of the exception?
 
The type System.Web.HttpException
in Assembly System.Web, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is not
marked as serializable
 
i believe my comments were qualified to say that it may or may not happen
depending on underlying OS.

True. Are you using IIS 6.0 IIS 5.0? Different models between them. I was
testing on IIS 5.0.

From the error message it looks like the exception is coming from another
app domain or process. Funny HttpException isn't marked as serializable,
since thats one of the first things you learn with .NET exceptions, make
them serializable since you don't know when your exception may cross app
domain boundaries. The class HttpException inherits from,
System.Runtime.InteropServices.ExternalException, is serializable but
HttpException is not. I might consider the lack of serializable marker on
that exception a bug, but either way this error probably preventing you from
seeing the true error.

What I would attempt to do is attach the debugger to the asp.net process,
there is a way to set the debugger to break on any exception thrown, there
might even be a way to filter for specific exception, I can't remember from
the steps from memory and I'm not sitting on a computer with VS.NET, and
this is something I haven't done for quite a while. At the point the
exception is thrown the debugger will break, start inspecting the memory at
the point and see if you can make heads or tails out of it. Basically you
just need the message from the HttpException before you get the not
serializable exception. Its a tough task if you have never done stuff like
this before but if you get through it you will learn a bunch. I suggest John
Robbins book on debugging.

I agree with you too on the lack of documentation on multi-threading in
ASP.NET applications.

Good Luck,
JD

Alvin Bruney said:
The type System.Web.HttpException
in Assembly System.Web, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is not
marked as serializable
 
i have robbins book. i know it intimately.

i have caught the exception live once or twice long ago when i was doing
some intensive threading but the debugger would never break into the line of
code, instead saying something to the fact that a line of code could not be
found and preferring instead to terminate abruptly. That usually happens
when a thread throws an exception but isn't around anymore. at least so i
thought.

the appdomain part is interesting. i've never considered it. i don't know
why another appdomain would be unloading either. or how another process
would come into play since a thread isn't a process anyway.

so strange. i'll have to let this one go since i can reproduce it.

--
Regards,
Alvin Bruney
[ASP.NET MVP http://mvp.support.microsoft.com/default.aspx]
Got tidbits? Get it here... http://tinyurl.com/27cok
JD said:
i believe my comments were qualified to say that it may or may not happen
depending on underlying OS.

True. Are you using IIS 6.0 IIS 5.0? Different models between them. I was
testing on IIS 5.0.

From the error message it looks like the exception is coming from another
app domain or process. Funny HttpException isn't marked as serializable,
since thats one of the first things you learn with .NET exceptions, make
them serializable since you don't know when your exception may cross app
domain boundaries. The class HttpException inherits from,
System.Runtime.InteropServices.ExternalException, is serializable but
HttpException is not. I might consider the lack of serializable marker on
that exception a bug, but either way this error probably preventing you
from
seeing the true error.

What I would attempt to do is attach the debugger to the asp.net process,
there is a way to set the debugger to break on any exception thrown, there
might even be a way to filter for specific exception, I can't remember
from
the steps from memory and I'm not sitting on a computer with VS.NET, and
this is something I haven't done for quite a while. At the point the
exception is thrown the debugger will break, start inspecting the memory
at
the point and see if you can make heads or tails out of it. Basically you
just need the message from the HttpException before you get the not
serializable exception. Its a tough task if you have never done stuff like
this before but if you get through it you will learn a bunch. I suggest
John
Robbins book on debugging.

I agree with you too on the lack of documentation on multi-threading in
ASP.NET applications.

Good Luck,
JD

Alvin Bruney said:
The type System.Web.HttpException
in Assembly System.Web, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is not
marked as serializable

--
Regards,
Alvin Bruney
[ASP.NET MVP http://mvp.support.microsoft.com/default.aspx]
Got tidbits? Get it here... http://tinyurl.com/27cok
Jon Skeet said:
<"Alvin Bruney [MVP]" <vapor at steaming post office>> wrote:
i believe my comments were qualified to say that it may or may not happen
depending on underlying OS.

I can't reproduce it either, at least for now. I know I am not insane
because I've found a couple of threads on the newsgroups which
produced
this
exception.

What's the message of the exception?
 
The type System.Web.HttpException
in Assembly System.Web, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is not
marked as serializable

None of that is the *message* of the exception though - you know, what
you get if you print out exception.Message.
 
Alvin, JD,

JD is absolutely right, this is a bug in V1.1, HttpException should be
marked Serializable, and this exception is hiding the real problem. One
possible causes could be a viewstate validation error, "viewstate
validation" code seems to run in a separate app domain on IIS6.
Alvin, I would suggest you to contact PSS and check with them if no hotfix
is available for this issue (the HttpException).

Willy.


JD said:
i believe my comments were qualified to say that it may or may not happen
depending on underlying OS.

True. Are you using IIS 6.0 IIS 5.0? Different models between them. I was
testing on IIS 5.0.

From the error message it looks like the exception is coming from another
app domain or process. Funny HttpException isn't marked as serializable,
since thats one of the first things you learn with .NET exceptions, make
them serializable since you don't know when your exception may cross app
domain boundaries. The class HttpException inherits from,
System.Runtime.InteropServices.ExternalException, is serializable but
HttpException is not. I might consider the lack of serializable marker on
that exception a bug, but either way this error probably preventing you
from
seeing the true error.

What I would attempt to do is attach the debugger to the asp.net process,
there is a way to set the debugger to break on any exception thrown, there
might even be a way to filter for specific exception, I can't remember
from
the steps from memory and I'm not sitting on a computer with VS.NET, and
this is something I haven't done for quite a while. At the point the
exception is thrown the debugger will break, start inspecting the memory
at
the point and see if you can make heads or tails out of it. Basically you
just need the message from the HttpException before you get the not
serializable exception. Its a tough task if you have never done stuff like
this before but if you get through it you will learn a bunch. I suggest
John
Robbins book on debugging.

I agree with you too on the lack of documentation on multi-threading in
ASP.NET applications.

Good Luck,
JD

Alvin Bruney said:
The type System.Web.HttpException
in Assembly System.Web, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a is not
marked as serializable

--
Regards,
Alvin Bruney
[ASP.NET MVP http://mvp.support.microsoft.com/default.aspx]
Got tidbits? Get it here... http://tinyurl.com/27cok
Jon Skeet said:
<"Alvin Bruney [MVP]" <vapor at steaming post office>> wrote:
i believe my comments were qualified to say that it may or may not happen
depending on underlying OS.

I can't reproduce it either, at least for now. I know I am not insane
because I've found a couple of threads on the newsgroups which
produced
this
exception.

What's the message of the exception?
 
Back
Top