Csharp async calls to Web Service that calls C++ :: blocking issue

B

Brian Parker

I inherited a C++ DLL that I need to remotely call multiple times
asynchronously. What I have developed is:

CSharp web application that makes asynchronous calls to a CSharp Web
Service. The Web Service calls the DLL, which does some heavy
processing, then sends the results back to the CSharp web application.

The problem is that the calls to the DLL in the Web Service are blocking
each other. If I send 10 async requests to the Web Service, debug
statements show that they all reach the call to the DLL within 1/10 of a
second, but only one call to the main method in the C++ DLL will run at
a time. If I stub off the call to the DLL and replace it with something
like a 15 second Sleep, the async Web Service calls all process
asynchronously as expected.

Is there an inherent reason why the DLL won't allow multiple calls to
its main method to run concurrently? Does anyone have a suggestion as
to why this is happening?

-BEP
 
J

jeremiah johnson

If you have the source code to the DLL, make sure the methods you're
calling aren't synchronized.

also, if the DLL has a method that calls another DLL somewhere that is
synchronized, you'll see the same effect.

You're describing synchronous behavior, so that what I'd say the cause is.
 
S

shumaker

If the DLL is dealing with any objects that are thread safe, and they
happen to try and access the same object for some reason(perhaps
something static in the DLL that all threads would be sharing) then
they will likely execute one at a time as they take they're turn with
the object.
 
B

Brian Parker

If the DLL is dealing with any objects that are thread safe, and they
happen to try and access the same object for some reason(perhaps
something static in the DLL that all threads would be sharing) then
they will likely execute one at a time as they take they're turn with
the object.

I've looked through the code and found a lot of static declarations in
methods. Almost all of them are utility methods that could be made
non-static. The other few, I'm not sure about but will look into.

I did find this in the code. Does it give any insight into the issue:

--CODE BEGIN-----------------------------------------
STDAPI DllCanUnloadNow(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return (AfxDllCanUnloadNow()==S_OK && _Module.GetLockCount()==0) ?
S_OK : S_FALSE;
}
--CODE END-------------------------------------------

Thanks to you guys for your suggestions so far.
-BEP
 
M

Mart

Hi Brian,
What version of C++ is the DLL written in?

Thanks. It's been a couple of years since I've done Visual C++ in
anger, but here's where I'd probably start (sorry if I'm teaching
grandma...):

1 - How has the C++ been compiled? Is it multi threaded or single
threaded?
2 - Is the C++ DLL COM or straight C++?
3 - How, where and by what is the C++ DLL being loaded? Which process
space is it running in? Does the model used allow multi threading or
multiple loading?
4 - Does the C++ have any forced syncrohnisation in it - any clues like
link syncs, mutexs, singleton pattern stuff etc?

I'm not sure about the mechanics of how .NET uses native C++ stuff. Are
there any restrictions in the way this works?

Cheers, Mart.
 
B

Brian Parker

Mart said:
Thanks. It's been a couple of years since I've done Visual C++ in
anger, but here's where I'd probably start (sorry if I'm teaching
grandma...):

Oops, I forgot. It was written in VC++ 6.0 but I made a very minor
change to some logic in it recently and recompiled in VStudio 2003. Not
sure if that makes a difference, but though it was worth a mention.
1 - How has the C++ been compiled? Is it multi threaded or single
threaded?

The DLL itself does threading. Here's a quick overview of what it does:
I send an array to the DLL. The DLL hits a web page for each member of
the array and brings back the HTML. It parses the HTML, sticks it in a
database for my C# program to retrieve, then returns. For each web page
it hits and reads, it spawns a thread. I'm going to assume it was
originally compiled multi-threaded. How can I tell?

I did searches on LIBC, LIBCMT, and MSVCRT and turned up nothing. I
don't see where in the IDE I can control the linker options - only how
to set them via the command-line, a command file, or via the ENV vars.
2 - Is the C++ DLL COM or straight C++?

I'm really not sure.
3 - How, where and by what is the C++ DLL being loaded? Which process
space is it running in? Does the model used allow multi threading or
multiple loading?

This is what I have to do to use it:
I register the DLL using regsrv32
In VStudio, I go under "Project -> Add Reference" and find it under the
COM tab - that may answer your previous question.
4 - Does the C++ have any forced syncrohnisation in it - any clues like
link syncs, mutexs, singleton pattern stuff etc?

It uses a few mutexes, but only when it accesses specific web pages, and
the 2 that use mutexes I'm not using in my testing so that code never
gets called.

One other place it uses mutexes is in the error handler. If there's an
error, it writes it to a log and the mutex is there to stop file errors.
I'm not sure about the mechanics of how .NET uses native C++ stuff. Are
there any restrictions in the way this works?

This is my first time with it. I'm not compiling the C++, I'm just
hooking into the DLL when my code runs. The DLL is already registered
in the system and waiting for something like my program to use it.

I don't think I gave you too many answers to your question, but
hopefully there's something there that may spark something. I
appreciate your help.

-BEP
 
M

Mart

Hi Brian,
Oops, I forgot. It was written in VC++ 6.0 but I made a very minor
change to some logic in it recently and recompiled in VStudio 2003. Not
sure if that makes a difference, but though it was worth a mention.

I suspect it might, but I've never tried so I can't be sure. To be on
the safe side, I'd want to compile the C++ using the VS6 C++ IDE to
eliminate this as a potential cause, as this (I am assuming!) is how
the orginial author of the DLL compiled it?
The DLL itself does threading. Here's a quick overview of what it does:
I send an array to the DLL. The DLL hits a web page for each member of
the array and brings back the HTML. It parses the HTML, sticks it in a
database for my C# program to retrieve, then returns. For each web page
it hits and reads, it spawns a thread.

I doubt whether the threads that the DLL is spawning internally will be
an issue - this sounds fine so long as there are no obvious design or
implementation features that would be actively holding a thread. I
suspect that the blocking is more likely to be associated with how the
calls into the routine that loops your Array are being managed by the
clients of your DLL (i.e. your C# and COM wapper - see below).
I'm going to assume it was originally compiled multi-threaded. How can I tell?
I did searches on LIBC, LIBCMT, and MSVCRT and turned up nothing. I
don't see where in the IDE I can control the linker options - only how
to set them via the command-line, a command file, or via the ENV vars.

As far as I remember it's in the Project Setting in the VS6 C++ IDE.
It's been a while, but I think to use Win32 multithreading you need to
set the runtime library to "Multithreaded DLL".
I'm really not sure.
3 - How, where and by what is the C++ DLL being loaded? Which process
space is it running in? Does the model used allow multi threading or
multiple loading?
This is what I have to do to use it:
I register the DLL using regsrv32
In VStudio, I go under "Project -> Add Reference" and find it under the
COM tab - that may answer your previous question.

Yep 3 answers 2! My understanding from what you say is that your C++
DLL is COM compliant.

There is plenty on COM on MSDN if you're uncertain and want to know
more about it (try www.microsoft.com/com). In case you're not aware,
COM (Component Object Model) is a framework that Microsoft introduced
to facilitate interoperability between software components without
those components knowing about each other's internals. COM allows you
to write components in different languages, and, so long as they are
COM-compliant, they can communicate with each other. You may have heard
of OLE and ActiveX? These are technologies within the COM umbrella
framework.

For your managed code (.NET C#) to interoperate with your COM DLL
(C++), a wrapper needs to be constructed which allows your C# to
communicate with your C++. Microsoft suggest using the Type Library
Importer tool to setup a .NET wrapper for a COM component that you wish
to call (see
http://msdn2.microsoft.com/en-US/library/ms173185(VS.80).aspx and
http://msdn2.microsoft.com/en-US/library/zeaxheha(VS.80).aspx for more
details). However, it may be the case that this is being run, and that
a wrapper is being created automatically for you, when you add the
reference to your project in the process you outline above. It's worth
checking that this done correctly!

I'm not sure how the wrappers created to allow you to call the COM
component work, so I don't know whether they will be synchronising
calls or not, preventing multiple loading or multithreading and so on.
Sorry I can't help anymore on this without researching it! :blush:)
It uses a few mutexes, but only when it accesses specific web pages, and
the 2 that use mutexes I'm not using in my testing so that code never
gets called.
One other place it uses mutexes is in the error handler. If there's an
error, it writes it to a log and the mutex is there to stop file errors.

Umm, might be worth following the logic through as best you can to see
whether these are holding something up.
This is my first time with it. I'm not compiling the C++, I'm just
hooking into the DLL when my code runs. The DLL is already registered
in the system and waiting for something like my program to use it.
I don't think I gave you too many answers to your question, but
hopefully there's something there that may spark something. I
appreciate your help.

No problem!

As a suggestion, one way to see whether it's your COM, the COM wrapper
or the C# might be to use write a test ASP classic page to load the COM
DLL and kick off the same COM process. Again it's been a while, but
something like:

<%
Dim myComThingy
myComThingy = Server.CreateObject("MyLib.MyComponent")
myComThingy.DoTheLoopStuff(anArray)
%>

Then call into this ASP Classic page multiple times and see what
happens. You'll need to make sure that the Virtual Directory that the
ASP page is in on IIS is setup to put ASP into a COM+ process rather
than loading it into the IIS process space (set the application
protection to Medium (Pooled) in the Virt Dir properties in IIS5).

If the COM does it's job without holding synching the calls, then
you'll know the COM works and your issue is on the C# or COM wrapper
side. If not, then you know it's the COM.

Hope this helps, Mart.
 
B

Brian Parker

<snip lots of good information from Mart>

I got it all figured out thanks to your hints and suggestions.

The DLL's project had been set to use a CComSingleThreadModel. I
changed this to CComMultiThreadModel in the header file and also changed
'Apartment' to 'Free' in the .rgs file. I wasn't sure if 'Free' was a
better choice than 'Both', though. It works, but still may not be correct.

Thanks for all the great information. Even though this is now working,
I'm still going to follow up on some of the things you suggested for
learning's sake.

-BEP
 
M

Mart

Hi Brain,

Ah, thought it might be so! Free threading might be you best option.

Apartment threading is where you have a number of "apartments" which
each run a single thread (imagine the OS as a block of apartments, in
each of which runs a seperate single thread). Apartment threaded COM
objects exist within an "apartment". This means that they are
single-threaded, but in the system at large (i.e. across many
apartments) a form of multithreading can happen because different
threads will be running through different instances of a COM component
in different apartments.

This also is the restriction of apartment threading: An instance of a
COM object (i.e. instance of your C++ DLL) will be running in a single
apartment, and will therefore be single threaded in itself, not
multithreaded. This also means that calls between COM objects sometimes
have to be marshalled across threads (i.e. between apartments).

Free threading is true multithreading, and means that multiple threads
can be running through one COM object. This is your best choice if you
want to have one instance of your COM object being accessed
simultaneously.

The disadvantage of free threading is that you have to make sure your
COM object is thread-safe (which, I assume, it is). In apartment
threading this is not necessary, since a *different* instance of your
COM component will be running singularly in *different* apartments;
therefore is single-threaded in itself and does not need to be
thread-safe.

Again, I expect google and MSDN can explain more than me!

Cheers, Mart.
 

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