Serializing a request for an ASP page containing COM objects

A

Anthony Jones

Bob Barrows said:
Michael said:
Anthony Jones wrote:
It should be pointed out that this will affect all uses of
application locks. If the application is to contain other pages (not
connected with the problem in question) use application locks these
pages will be affected also. IOW the Application object itself can
be used as a single global mutex.

As clearly documented by Microsoft.
Personally I prefer Egbert's solution.

Certainly Egbert's is the most general solution. But no debugged code
was provided.

In it's favor, my suggestion is quick, easy to apply, clearly works as
designed by Microsoft and the tested code is provided above.

My suggestion will work until that mutex method is written and
debugged. Or even forever, if need be. [Yes, billions and billions of
ASP pages running until the _end_ _of_ _time_, bwaahaahaaahaaaa!]

My suggestion is certainly better than the two you suggested earlier:
1-enable debugging or
2-setting AspProcessorThreadMax to 1
which were both very amusing. Thanks for the laugh.

All in all, I think you're embarrassed that you missed this most
obvious suggestion, one designed by Microsoft. Reason I say that is
that, in the example you gave where you stored an object into the
Application object, you neglected to lock and unlock the Application
object, a common newbie error. Just a guess; I could be wrong, of
course.

Is there some history between you two here?

None that I''m aware of although I'll admit I am woefully lacking in the
social graces department so perhaps my blunt sounding posts may have upset
him at some point.
This is verging on being
insulting (perhaps even crossing the line), and Im not sure the insult
was called for.

Probably was. I was criticising his suggestion which clearly superior to any
of mine. ;)
From what I could see, Anthony was expressing a
preference for a technique, not disparaging yours, which he did
acknowledge would accomplish the OP's purpose.

I am sure that Anthony is aware of the need to lock Application, and
simply left it out of his example because he was sure I was aware of the
need to do that as well.

Indeed it wasn't really needed for point being demonstrated.
 
D

Daniel Crichton

Anthony wrote on Wed, 2 Aug 2006 15:44:44 +0100:
What happens if you don't call Lock, Unlock?

Any other request can change the value of Application("x") outside of the
current ASP thread, effectively breaking the serialisation on the initial
calls. Using Lock will prevent it being changed by another request until the
Unlock method is called.

Dan
 
D

Daniel Crichton

Daniel wrote to Anthony Jones on Wed, 2 Aug 2006 16:35:11 +0100:
Anthony wrote on Wed, 2 Aug 2006 15:44:44 +0100:


Any other request can change the value of Application("x") outside of the
current ASP thread, effectively breaking the serialisation on the initial
calls. Using Lock will prevent it being changed by another request until
the Unlock method is called.

Dan

Oops, forgot to also mention that the ASP page that get the Lock on first
will cause all the others to wait until Unlock is called, they won't just
skip the setting of the Application variable.

Dan
 
A

Anthony Jones

Bob Barrows said:
How does one create a mutex in vbscript without using
application.lock...unlock?

None that I know of but creating a small component to do this shouldn't be
too hard. If I really needed it it's what I'd do but not without vigorously
trying to avoid it altogether.
I was not aware that thread could be created in scripting ...

No thread creation is needed.
 
A

Anthony Jones

Daniel Crichton said:
Anthony wrote on Wed, 2 Aug 2006 15:44:44 +0100:


Any other request can change the value of Application("x") outside of the
current ASP thread, effectively breaking the serialisation on the initial
calls. Using Lock will prevent it being changed by another request until the
Unlock method is called.

Dan

Thanks for taking the time to answer my question. However I have to be
honest and admit I was being facetious.

Apart from the fact the that with or without a lock the code fails miserably
anyway why does simply assigning a value to the application object require a
lock? With a lock anything that wants to change it will, as soon as the
lock is released, so why bother?

Now this:-

Application("myNumber") = Application("myNumber") + 1

or the substance thereof does need a lock. In the time between reading
myNumber and re-assigning it back it is probably undesirable that anything
else is reading and assigning it.

Or is there something I'm missing?

Anthony.
 
M

Max

Anthony Jones said:
It should be pointed out that this will affect all uses of application
locks. If the application is to contain other pages (not connected with
the
problem in question) use application locks these pages will be affected
also.

IOW the Application object itself can be used as a single global mutex.
Personally I prefer Egbert's solution.
Thanks everyone for their answers.

I have been considering your suggestions and the possible consequences of
locking the whole application and would like your input on another
possibility coming out of Egbert's mutex solution.

If I were to wrap the COM object in a process lock (unname mutex or critical
section) which would prevent multiple requests through the same process AND
use a web garden to allow multiple requests on the same page to use
different processes, I might be able to overcome the performance penalty of
a global lock. Any thoughts, experiences or that won't work because ...
would be appreciated.

Thanks
Max
 
A

Anthony Jones

Max said:
Thanks everyone for their answers.

I have been considering your suggestions and the possible consequences of
locking the whole application and would like your input on another
possibility coming out of Egbert's mutex solution.

If I were to wrap the COM object in a process lock (unname mutex or critical
section) which would prevent multiple requests through the same process AND
use a web garden to allow multiple requests on the same page to use
different processes, I might be able to overcome the performance penalty of
a global lock. Any thoughts, experiences or that won't work because ...
would be appreciated.

Now your requirements are less clear. The problem is we don't know why you
need to serialise access to the COM object. Perhaps you could elaborate?

It appears from the above (correct me if I'm wrong) that you are a happy for
the same page to run concurrently if running in different processes, this
suggests to me that you are trying to use a component which is not thread
safe.
 
D

Daniel Crichton

Anthony wrote on Wed, 2 Aug 2006 17:07:39 +0100:
Thanks for taking the time to answer my question. However I have to be
honest and admit I was being facetious.

After I'd posted my reply I did wonder, as you seemed to understand from
replies in other branches that you know what Lock/Unlock does. I didn't see
that a followup from me was needed though.
Apart from the fact the that with or without a lock the code fails
miserably anyway why does simply assigning a value to the application
object require a lock? With a lock anything that wants to change it will,
as soon as the lock is released, so why bother?

Because by assigning an apartment/single threaded object into it you force
ASP into serialising all further page processing. The Lock/Unlock ensures
that if there are a couple of concurrent requests when the application is
first hit that they are then processed serially - if you don't use
Lock/Unlock there's a chance, albeit very slim, that a few requests might
get executed concurrently as they attempt to initialise the Application
variable simultaneously.
Now this:-

Application("myNumber") = Application("myNumber") + 1

or the substance thereof does need a lock. In the time between reading
myNumber and re-assigning it back it is probably undesirable that anything
else is reading and assigning it.

Or is there something I'm missing?

Maybe the thread topic of serialising the requests?

Dan
 
A

Anthony Jones

Daniel Crichton said:
Anthony wrote on Wed, 2 Aug 2006 17:07:39 +0100:


After I'd posted my reply I did wonder, as you seemed to understand from
replies in other branches that you know what Lock/Unlock does. I didn't see
that a followup from me was needed though.


Because by assigning an apartment/single threaded object into it you force
ASP into serialising all further page processing

Try my code. Add Lock/Unlock if you like. It doesn't work. The
application object will not store references to STA objects. Which is the
point I was illustrating.
The Lock/Unlock ensures
that if there are a couple of concurrent requests when the application is
first hit that they are then processed serially - if you don't use
Lock/Unlock there's a chance, albeit very slim, that a few requests might
get executed concurrently as they attempt to initialise the Application
variable simultaneously.

OK what happens if an application variable is updated simultaneously by
concurrently running ASP pages? Bear in mind the the Application object is
thread safe. Having considered what actually happens, in what way is it
different from when Lock/Unlock is used?

Have a look at this:-

Application("thing1") = AValue
Application("thing2") = AnotherValue

There is a reason why you might want this protected by Lock/Unlock what is
it?

Now in another page we have this the application variables are just being
read:-

AValue = Application("thing1")
AnotherValue = Application("thing2")

does this need Lock/Unlock?
 
D

Daniel Crichton

Anthony wrote on Thu, 3 Aug 2006 11:35:44 +0100:
Try my code. Add Lock/Unlock if you like. It doesn't work. The
application object will not store references to STA objects. Which is the
point I was illustrating.

I've stored ADO apartment threaded objects in it before. I won't ever do it
again. That was the first mistake I made on my first ASP application.
OK what happens if an application variable is updated simultaneously by
concurrently running ASP pages? Bear in mind the the Application object
is thread safe. Having considered what actually happens, in what way is
it different from when Lock/Unlock is used?

I guess my understanding of threading is rusty and outdated. I'll have to go
back and read up, and concede that I'm probably wrong. Putting values like
strings into the Application object wasn't the point of my reply - storing
references to objects that are not free threaded was.

Dan
 
A

Anthony Jones

Daniel Crichton said:
Anthony wrote on Thu, 3 Aug 2006 11:35:44 +0100:


I've stored ADO apartment threaded objects in it before. I won't ever do it
again. That was the first mistake I made on my first ASP application.

Nope it just looks that way. What you've been storing a free threaded proxy
to the ADO object.
I guess my understanding of threading is rusty and outdated. I'll have to go
back and read up, and concede that I'm probably wrong. Putting values like
strings into the Application object wasn't the point of my reply - storing
references to objects that are not free threaded was.

I don't think you're wrong necessarily just unsure why you are right. ;)
 
D

Daniel Crichton

Anthony wrote on Thu, 3 Aug 2006 14:02:34 +0100:
Nope it just looks that way. What you've been storing a free threaded
proxy to the ADO object.

OK, but that still, according to MS, will result in the ASP requests being
serialised, right? In which case there is some marshalling going on to the
apartment threaded objects that the proxy is referencing, and given that the
proxy is free threaded doesn't this lend weight to the possibility that
having two simultaneous requests trying to assign an ADO (or other apartment
threaded object) into the Application object could cause those two requests
to not be serialised? Using Lock/Unlock would force the serialisation by
preventing one of those ASP pages from trying to add a reference to the
object to the Application object while the other request was doing so. Or
would the fact that the object is apartment threaded anyway mean that the
proxy on one request would be queued behind the other for access to the
object?

Dan

Dan
 
A

Anthony Jones

Anthony Jones said:
Try my code. Add Lock/Unlock if you like. It doesn't work. The
application object will not store references to STA objects. Which is the
point I was illustrating.


OK what happens if an application variable is updated simultaneously by
concurrently running ASP pages? Bear in mind the the Application object is
thread safe.

Since the application object is thread safe it isn't going let multiple
threads modify it's internal structures at the same time. Hence any
simultaneous attempts to modify the contents will cause one thread to
continue and the others to block until the one thread is finished. Each
thread will make consistent changes one after the other. The last one to
make changes wins as it were.
Having considered what actually happens, in what way is it
different from when Lock/Unlock is used?

It isn't different. Updates to a single value in the application object are
serialised whether you use lock or not.
Have a look at this:-

Application("thing1") = AValue
Application("thing2") = AnotherValue

There is a reason why you might want this protected by Lock/Unlock what is
it?

If it is important that the value assigned from AValue is consistent with
AnotherValue then this needs a Lock otherwise it is possible that in between
assigning AValue and AnotherValue the thread could be bumped off the CPU and
another request to the same page makes different changes. Once the original
thread resumes it will assign AnotherValue and the application will end up
with AnotherValue from this thread and AValue from the other thread.
Now in another page we have this the application variables are just being
read:-

AValue = Application("thing1")
AnotherValue = Application("thing2")

does this need Lock/Unlock?

Assuming that AValue and AnotherValue need to be consistent with when they
were assigned then yes it needs a lock. For pretty much the same reason as
above.
 
A

Anthony Jones

Daniel Crichton said:
Anthony wrote on Thu, 3 Aug 2006 14:02:34 +0100:


OK, but that still, according to MS, will result in the ASP requests being
serialised, right?

If you mean that all requests to ASP will from now on go to the same thread
and have to queue one after the other then no. I'm not sure you meant that
though.
In which case there is some marshalling going on to the
apartment threaded objects that the proxy is referencing,

Yep when any worker thread (and there can still be many) attempts to use the
stored object any call to the object will be marshalled to the original
thread that created the object.

Ultimately this can result in a massive cross thread marshalling to this one
poor thread that pretty much is being asked to do all the applications ADO
activity single handed. Not good. ;)
and given that the
proxy is free threaded doesn't this lend weight to the possibility that
having two simultaneous requests trying to assign an ADO (or other apartment
threaded object) into the Application object could cause those two requests
to not be serialised?

The proxy is free threaded so two requests can attempt to make a call on it
simutaneously, the proxy will happily create two simultaneous cross thread
calls but one will block until the other completes.
Using Lock/Unlock would force the serialisation by
preventing one of those ASP pages from trying to add a reference to the
object to the Application object while the other request was doing so.

Not using a lock does the same. Only one thread can make a modification to
the application object at the same time with or without a lock.

The proxy assigned first will then immediately be released as the proxy from
the second gets assigned. The last thread to make the assignment becomes
the victim of an onslaught of calls from other threads wanting the services
of the ADO object it has. The other ADO objects that had fleeting been
assigned will be destroyed when their requests complete or before.
Or
would the fact that the object is apartment threaded anyway mean that the
proxy on one request would be queued behind the other for access to the
object?

Only one proxy gets stored.
 
D

Daniel Crichton

Anthony wrote on Thu, 3 Aug 2006 14:47:23 +0100:
If you mean that all requests to ASP will from now on go to the same
thread and have to queue one after the other then no. I'm not sure you
meant that though.

I felt sure years ago when I first started ASP development that MS had
published an article that said exactly this. However all I can find now are
articles about how it will serialise only the specific Session, not the
Application, and cause ADO objects to remain memory resident (which was the
other reason I very quickly changed my programming back then).

Looks like I've learnt something new again, but still reinforced the
recommendations I give to customers that putting ADO objects (and I tend to
apply the same rule to all objects) in the Session/Application object is a
bad idea.

Dan
 
D

Daniel Crichton

Daniel wrote to Anthony Jones on Thu, 3 Aug 2006 15:23:39 +0100:
Anthony wrote on Thu, 3 Aug 2006 14:47:23 +0100:

Now I remember where I've seen it. VB COM objects that use STA and placed in
the Session object will, according to http://support.microsoft.com/default.aspx/kb/243548
and http://support.microsoft.com/default.aspx/kb/243543 , cause subsequent
requests for the object to be executed on the thread that placed the object
into the Session and therefore serialising them. I must have misread these
to imply that all ASP threads would be serialised, not just the ones for a
particular Session ID.

Dan
 
A

Anthony Jones

Daniel Crichton said:
Anthony wrote on Thu, 3 Aug 2006 14:47:23 +0100:


I felt sure years ago when I first started ASP development that MS had
published an article that said exactly this. However all I can find now are
articles about how it will serialise only the specific Session, not the
Application, and cause ADO objects to remain memory resident (which was the
other reason I very quickly changed my programming back then).

I think one problem is the use of word serialise. What you are describing
here is the affiliation of a session with a thread. This subsequently leads
to multiple requests for different sessions being serialised due having
become affiliated with the same work thread. There can other sets of
sessions affiliated with other threads but overall scalability of the
application is significantly impaired.

Requests for a single session are always serialised which is to say that ASP
only executes one request per session at a time. Subsequent requests for
the same session may run on different threads but not simultaneously. This
is because the Session object is single threaded.

The only time an entire application has all ASP requests serialised is when
it only has one worker thread or is in debug mode.
 
M

Michael D. Kersey

Max wrote:
Thanks everyone for their answers.
I have been considering your suggestions and the possible consequences of
locking the whole application and would like your input on another
possibility coming out of Egbert's mutex solution.

If I were to wrap the COM object in a process lock (unname mutex or critical
section) which would prevent multiple requests through the same process AND
use a web garden to allow multiple requests on the same page to use
different processes, I might be able to overcome the performance penalty of
a global lock. Any thoughts, experiences or that won't work because ...
would be appreciated.

Perhaps there is undue concern about an imagined possible "performance
penalty".

1. Is your COM object a CPU hog?
2. Do your ASP pages already contain many calls to Application.Lock?

If the answer to both questions is "yes", you _may_ _possibly_ incur
some performance penalty by using the Application object's Lock and
Unlock methods to cordon off your COM component.

If the answer to either question is "no", then I doubt you will see any
significant performance penalty.

Don't be afraid to try a ready, quick and easy solution. Microsoft saw a
need and added these methods so ASP developers could use them. Avoiding
their use is suboptimal. Certainly the goal in your original post:
... to ensure that a
request for a particular ASP page is finalized before another request for
the page is processed
can be tested using these methods (we _are_ talking about two lines of
ASP code here). If they work, you're home free. If they fail, then
you've got another problem. If they work, but fail under load, then
you'll need to find another solution.
 
A

Anthony Jones

Michael D. Kersey said:
Max wrote:


Perhaps there is undue concern about an imagined possible "performance
penalty".

1. Is your COM object a CPU hog?
2. Do your ASP pages already contain many calls to Application.Lock?

It's not just Application.Lock that's involved here. For the duration of
the application lock nothing else can use the application lock not even a
simple read.

If the COM object performs an operation that requires any appreciable
elapsed time (regardless of whether the it's a CPU hog or not) then the
application can be significantly affected as requests stall trying to read
the application object whilst it's locked by this operation.

If the answer to both questions is "yes", you _may_ _possibly_ incur
some performance penalty by using the Application object's Lock and
Unlock methods to cordon off your COM component.

If the answer to either question is "no", then I doubt you will see any
significant performance penalty.

Don't be afraid to try a ready, quick and easy solution. Microsoft saw a
need and added these methods so ASP developers could use them.

Not for this job they didn't. Lock is there to avoid race conditions when
modifying multiple values.
Avoiding
their use is suboptimal. Certainly the goal in your original post:
can be tested using these methods (we _are_ talking about two lines of
ASP code here). If they work, you're home free. If they fail, then
you've got another problem. If they work, but fail under load, then
you'll need to find another solution.

If all you have is a hammer everything looks like a nail. Many ASP
developers have more tools in their tool box. It isn't rocket science to
create a small COM wrapper round a mutex and now you have the right tool for
the job. Using Lock in this way is just setting yourself up for problems in
the future. (As is using debug mode or changing the worker thread count I
might add). All daft ideas. If you gonna do a job you might as well do it
right.
 
M

Max

Anthony Jones said:
It's not just Application.Lock that's involved here. For the duration of
the application lock nothing else can use the application lock not even a
simple read.

If the COM object performs an operation that requires any appreciable
elapsed time (regardless of whether the it's a CPU hog or not) then the
application can be significantly affected as requests stall trying to read
the application object whilst it's locked by this operation.



Not for this job they didn't. Lock is there to avoid race conditions when
modifying multiple values.


If all you have is a hammer everything looks like a nail. Many ASP
developers have more tools in their tool box. It isn't rocket science to
create a small COM wrapper round a mutex and now you have the right tool
for
the job. Using Lock in this way is just setting yourself up for problems
in
the future. (As is using debug mode or changing the worker thread count I
might add). All daft ideas. If you gonna do a job you might as well do
it
right.
The COM object is very complex. It is single threaded and also maintains
state in the process between calls (using global variables and the like!)
and there are multiple calls to it from our customers web page. Yes I know
that is not how a good COM object is written but there is lots and lots of
legacy code in it!!). It cleans up on PageEnd so that the next request will
be treated correctly. Normally it would not run for a long time, however it
reads and executes byte code that is provided by our customers so "anything
may happen". It is however multiuser safe so that 2 or more processes do
not interfer with each other.

I was hoping that the idea to wrap it in a process lock would protect the
process state and to use a web garden would help with performance.
 

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

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top