Ureader.com  
Microsoft software help and Community
   home   |   control panel login   |   archive   |  
 
platform
active.directory
adsi
adsi.iis-admin
base
com_ole
complus_mts
component_svcs
database
directx
gdi
graphics_mm
internet.client
internet.server
internet.server.isapi-dev
localization
mapi
messaging
msi
mslayerforunicode
multimedia
networking
networking.ipv6
sdk_install
security
shell
telephony.tapi_2
telephony.tapi_3
telephony.tsp
telephony.wte
tools
ui
ui_shell
win_base_svcs
win16
  
 
date: Fri, 31 Aug 2007 09:54:41 -0400,    group: microsoft.public.platformsdk.com_ole        back       


Threads in MTA creating STA objects strangeness.   
i have multiple threads running in the MTA (multithreaded apartment). Each 
thread constructs a single WinHttpRequest object, which is a  single STA 
(single threaded apartment) object.  The thread then repeatedly fetches 
content and when finished frees the object.

The strangeness is that even though i have three threads running, the actual 
fetching of content over the network is being done serially.   If a request 
takes 1 second to complete, and i have 3 threads running, then the time to 
fetch data of a particular request will be either 1, 2, or 3 seconds.  If i 
have 5 threads running, then the time for a thread to receive data will be 
either 1, 2, 3, 4, or 5 seconds.


Now the smart ones among you will already know what's going wrong, and how 
to fix it. And i did randomly try that, and it did work. What we're trying 
desperatly to figure out is Why. Scouring MS documentation, what is 
happening is not what is documented.  But first we'll have to go through 
everything else i tried...



At first i thought that the web server was limiting each client machine 
(client ip) to one request. i know web servers typically limit the number of 
simultaneous connection requests from one machine. But it's usually limited 
to three connections, not one. Also, if i launch three applications, each 
spawning one thread, then the response times for all three are 1 second. Web 
servers don't know the process id of the client making the request, so that 
can't be it. This makes no sense.


Next i thought maybe there was an option in WinHttpRequest itself - that it 
limits it's number of simultaneous connections to 1. But i couldn't belive 
that MS would do that, such a feature makes no sense. Plus, how would the do 
it, how could they do it. And finally, why would it be that it only limits 
you in one process to one request at a time, and another process can issue 
another single request.  That makes no sense.


So i'm back to wondering how three threads, each creating their own object, 
can have access to that object serialized with two other threads.  How can 
the object created by Thread B possibly be not allowed to run while Thread A 
is talking to it's own object? It makes no sense.


Then i remember some tid-bit of innane trivia i heard one: each process only 
gets one MTA apartment, and all MTA threads share that apartment.  MTA means 
that the threads are free to stomp all over each other, which is not a 
problem in my case since we don't do any stomping of any kind.  STA means 
COM will step in and protect everyone from talking to objects from the wrong 
thread - but since i'm only ever talking to my WinHttpRequest object from 
the thread that created it, i don't need to worry about that.  But then we 
realized that even though i'm talking to the WinHttpRequest object in a 
thread safe manner, the thread is in an/the MTA apartment, while the 
WinHttpRequest object claims to only support being in an STA apartment. 
Okay, so this is interesting. The apartment the thread is incompatible with 
the threading model required by the WinHttpRequest.


Now the question is what does COM do if my thread, inside the MTA apartment, 
tries to create an object that requires to be used from an STA apartment? 
Consulting the documentation:

http://msdn2.microsoft.com/en-us/library/ms809971.aspx
Understanding and Using COM Threading Models
    Client: MTA
    Server: STA
    Server created in: A new STA, created by COM
    Inter-object communication via: Marshalling

Interesting. COM will launch a new thread, put the thread in it's own STA 
apartment, create the COM object, and give me a proxy stub interface. And 
anytime i want to call a method on that object COM will:
    - serialize the method parameters
    - send a message to the STA thread which says to run the method (because 
it's a SendMessage, my thread is suspended)
    - executes the method from the context of the STA thread on the real 
object
    - marshall the results back

and my thread resumes, with execution complete. Okay, that's all well and 
good. It explains how my thread can be suspended while a method call gets 
transferred to another thread. But it doesn't explain how two independant 
threads ThreadB and ThreadC can be suspended while ThreadA talks to it's 
object.


Perhaps COM only ever created one WinHttpRequest object? Perhaps because all 
MTA threads live in one apartment, and the COM object must be in an STA 
apartment, COM will do an optimization and only ever create one object. 
Since it promises to serialize all access to that single object, the object 
has been made thread safe.   No, that can't be. If three threads were to 
talk to the same object, even though a single method call access is 
protected, there's state information associated with the WinHttpRequest 
object. The three threads would stomp all over each others settings. That 
makes no sense.


So i try to reason this out:
    1. i created three threads.
    2. Each thread enters the MTA apartment
    3. Each thread creates it's own WinHttpRequest object
    4. Because the thread's apartment model is incompatible with objects 
apartment model, COM spawns three additional threads, one for each COM 
object.
    5. Each thread calls a method on the COM object.
    6. Each thread is suspended while a message is sent to each of the three 
STA apartment threads that hold the three com objects.
    7. Each STA thread executes the method, and returns the result.
    8. Each thread get's it's result.

Each thread *should* takes about 1 second to return it's result, and yet 
evidence shows that the access to the WinHttpRequst objects is being 
serialized through one thing.  What is the one thing through which all 
access to these objects is being funneled?


A colleague proposed a theory: What if COM is only creating one STA thread 
to handle all three of these inter-apartment COM objects?  That would 
explain it, COM must be creating only one thread to handle all these out of 
apartment objects, rather than a separate thread for each object.  But that 
can't be it, the documentation says quite clearly:

http://msdn2.microsoft.com/en-us/library/ms809971.aspx
Understanding and Using COM Threading Models
    Client: MTA
    Server: STA
    Server created in: A new STA, created by COM
    Inter-object communication via: Marshalling

"A new STA, created by COM"

When the threading model of the server is incompatible with the threading 
model of the server, the COM object is created in a *NEW* STA, not an 
existing STA.

    "A new STA, created by COM"

In reality, it's not being created in a new STA, it's being created in an 
existing STA. This is a problem with COM, because it's leaking an 
implementation detail rather than abstracting it.  And yet, it makes no 
sense that COM would only use a single thread to handle all these out of 
apartment objects. The performance contention is just horrendous. That makes 
no sense.

And yet, if i change the threads to enter their own STA apartment, none of 
the delays happen. Each thread then receives a response in about 1 second, 
rather than 1,2, or 3 seconds.


So what is actually going on that three MTA threads, each talking to their 
own STA object have serial access to the three STA objects. And if i change 
the threads to STA threads, each thread get's fast access? COM creating only 
a single thread for all out of apartment objects would explain it - but 
that's just a bad design idea, plus it violates the documentation.


This makes no sense.
date: Fri, 31 Aug 2007 09:54:41 -0400   author:   Ian Boyd

Re: Threads in MTA creating STA objects strangeness.   
The Service Control Manager (SCM) puts instances of classes marked as apartment-threaded that are created from an MTA or a TNA into 
a process's Host STA. From Tim Ewald's book (page 124): "The Host STA is created and managed by the plumbing specifically to house 
objects that require a high degree of thread affinity (ie. an STA environment), but that are created from the MTA or TNA."

Thus, all three instances of the WinHttpRequest object are in the same STA. This is clearly reflected in the behaviour that you are 
describing. Because they are in the same STA, the methods and properties are being served by the same thread, and hence access is 
being serialized.

>
> Interesting. COM will launch a new thread, put the thread in it's own STA apartment, create the COM object, and give me a proxy 
> stub interface.

This is incorrect. The second instantiated object will join the same host STA as the first instantiated object.

>
> So i try to reason this out:
>    1. i created three threads.
>    2. Each thread enters the MTA apartment
>    3. Each thread creates it's own WinHttpRequest object
>    4. Because the thread's apartment model is incompatible with objects apartment model, COM spawns three additional threads, one 
> for each COM object.

Wrong. All three threads belong to the same MTA. Any WinHttpRequest objects that are instantiated are created in the same STA.


> A colleague proposed a theory: What if COM is only creating one STA thread to handle all three of these inter-apartment COM 
> objects?  That would explain it, COM must be creating only one thread to handle all these out of apartment objects, rather than a 
> separate thread for each object.  But that can't be it, the documentation says quite clearly:
>
> http://msdn2.microsoft.com/en-us/library/ms809971.aspx
> Understanding and Using COM Threading Models
>    Client: MTA
>    Server: STA
>    Server created in: A new STA, created by COM
>    Inter-object communication via: Marshalling
>
> "A new STA, created by COM"
>
> When the threading model of the server is incompatible with the threading model of the server, the COM object is created in a 
> *NEW* STA, not an existing STA.

I believe this is true if the COM server were an executable rather than in-proc DLL. However, for in-proc DLL's the STA actually 
belongs to the host, and not the COM server. This is what Tim Ewald is describing when he talks about the "host STA".

The first object is indeed created in a new STA, called the host STA. However, the second object joins the first object in the same 
STA.

>
>    "A new STA, created by COM"
>
> In reality, it's not being created in a new STA, it's being created in an existing STA.

... as explained.

> This is a problem with COM, because it's leaking an implementation detail rather than abstracting it.

I have no clue what you mean by this.

>  And yet, it makes no sense that COM would only use a single thread to handle all these out of apartment objects.

Well, it makes complete sense if you are the author of the STA COM object. It allows one to focus on the implementation details 
without worring about thread-safety.

> The performance contention is just horrendous. That makes no sense.

Well, you have chosen to use the WinHttpRequest COM object, which was designed for VB apps. VB apps use STA's.

Frankly, why don't you write your own WinHttpRequest object and make it free-threaded? Or simply use the WinInet API directly?

HTH,

Brian
date: Fri, 31 Aug 2007 10:09:30 -0700   author:   Brian Muth

Re: Threads in MTA creating STA objects strangeness.   
> Frankly, why don't you write your own WinHttpRequest object and make it 
> free-threaded? Or simply use the WinInet API directly?

Object oriented programming. Some vender already took the time to write a 
http client implementation, that is wrapped up in a very easy to use 
interface.  i prefer to reuse their code, rather than re-inventing the 
wheel.
date: Fri, 31 Aug 2007 14:23:05 -0400   author:   Ian Boyd

Re: Threads in MTA creating STA objects strangeness.   
"Ian Boyd"  wrote in message news:u0QW6v$6HHA.3528@TK2MSFTNGP04.phx.gbl...
>> Frankly, why don't you write your own WinHttpRequest object and make it free-threaded? Or simply use the WinInet API directly?
>
> Object oriented programming. Some vender already took the time to write a http client implementation, that is wrapped up in a very 
> easy to use interface.  i prefer to reuse their code, rather than re-inventing the wheel.

Try launching three threads, but each thread calls CoCreateInstance(0). Each thread will establish an independent STA, and when they 
instantiate WinHttpRequest, each will be in separate STA apartments. I think you will be gratified in a major performance boost.

Brian
date: Fri, 31 Aug 2007 12:18:09 -0700   author:   Brian Muth

Re: Threads in MTA creating STA objects strangeness.   
> Try launching three threads, but each thread calls CoCreateInstance(0). 
> Each thread will establish an independent STA, and when they instantiate 
> WinHttpRequest, each will be in separate STA apartments. I think you will 
> be gratified in a major performance boost.

Yeah, that was the change that had to be made to make it usable. i nievely 
confused "MTA" with "free-threaded", and the idea of "don't do anything with 
synchronizing, i want to run free".

Turns out that MTA causes the most synchronization locks - not the least.
date: Wed, 10 Oct 2007 15:10:23 -0400   author:   Ian Boyd

Google
 
Web ureader.com


    COPYRIGHT 2007, YARDI TECHNOLOGY LIMITED, ALL RIGHT RESERVE  |   contact us