static members in multi-thread environment

M

mflanagan

I have unmanaged C++ program that will load a managed C++ dll and then
call a function in that dll. The managed C++ routine will call some C#
routines. The unmanaged C++ main program will make these calls (to
the managed C++ dll) many times, from many different threads. Each
thread will do a LoadLibrary, call one C++ routine in the managed dll,
and upon return, unload the library and exit.

I'm concerned about class variables (static) in my C# classes. I would
like such variables to have a scope (if that's the right word) of the
thread, or the time between load- and unload-library.

How do static class variables work in this regard? I *don't* want to
share these members across threads. And, if the same thread does a

"load-library; call function_in_dll(); unload library"

twice, I'd rather not have the second invocation of function_in_dll()
see the class variable from the first invocation.

Am I confusing the fact that .NET uses dlls with the usage of non-.NET
dlls?

Thanks for any insights into this.
 
J

Jon Skeet [C# MVP]

I have unmanaged C++ program that will load a managed C++ dll and then
call a function in that dll. The managed C++ routine will call some C#
routines. The unmanaged C++ main program will make these calls (to
the managed C++ dll) many times, from many different threads. Each
thread will do a LoadLibrary, call one C++ routine in the managed dll,
and upon return, unload the library and exit.

I'm concerned about class variables (static) in my C# classes. I would
like such variables to have a scope (if that's the right word) of the
thread, or the time between load- and unload-library.

In that case, I think you're after the ThreadStaticAttribute.
How do static class variables work in this regard? I *don't* want to
share these members across threads. And, if the same thread does a

"load-library; call function_in_dll(); unload library"

twice, I'd rather not have the second invocation of function_in_dll()
see the class variable from the first invocation.

I don't know enough about what load-library and unload-library will do,
but it's quite possible that this will just drop out.
 
W

Willy Denoyette [MVP]

I have unmanaged C++ program that will load a managed C++ dll and then
call a function in that dll. The managed C++ routine will call some C#
routines. The unmanaged C++ main program will make these calls (to
the managed C++ dll) many times, from many different threads. Each
thread will do a LoadLibrary, call one C++ routine in the managed dll,
and upon return, unload the library and exit.

I'm concerned about class variables (static) in my C# classes. I would
like such variables to have a scope (if that's the right word) of the
thread, or the time between load- and unload-library.

How do static class variables work in this regard? I *don't* want to
share these members across threads. And, if the same thread does a

"load-library; call function_in_dll(); unload library"

twice, I'd rather not have the second invocation of function_in_dll()
see the class variable from the first invocation.

Am I confusing the fact that .NET uses dlls with the usage of non-.NET
dlls?

Thanks for any insights into this.

Seems like you are mis-understanding the way managed code is loaded and
executed. Managed assemblies (DLL's, EXE's created by managed code
compilers/linkers) cannot be loaded/unloaded using Win32's
LoadLibray/FreeLibray API's. Managed assemblies are loaded by the CLR into
an application domain and can only be unloaded by unloading the application
domain.
Another point is that you can't directly call managed code methods from
native C++, you have to use COM interop for this.

Willy.
 
M

mflanagan

Seems like you are mis-understanding the way managed code is loaded and
executed. Managed assemblies (DLL's, EXE's created by managed code
compilers/linkers) cannot be loaded/unloaded using Win32's
LoadLibray/FreeLibray API's. Managed assemblies are loaded by the CLR into
an application domain and can only be unloaded by unloading the application
domain.
Another point is that you can't directly call managed code methods from
native C++, you have to use COM interop for this.

Willy.

Willy, thanks for the info. I'm afraid my poor explanation is causing
some misunderstanding. I have an unmanaged DLL that calls a managed
C++ DLL, but it doesn't do a LoadLibrary on it. (My unmanaged main
does a LoadLibrary on my unmanaged DLL; sorry about that.)

I assure you, though, that I am not using COM interop (at least, not
explicitly). I simply create the managed C++ DLL (and its associated
dll exports in a .h file, and a .lib file), and I compile my unmanaged
C++ against the .h file, and link my unmanaged C++ against the .lib.
Then, at runtime, when I call one of the managed C++ routines, the
system loads the managed runtime and calls my managed C++. I don't
call any COM functions in any of my DLLs. I've used COM before, and
I'm familiar with what's necessary to call COM objects/routines.

unmanaged main
LoadLibrary of unmanaged C++ DLL
Call routine in just loaded unmanaged C++ DLL
call to managed C++ (simple call)
call to various C# routines

BTW, my managed C++ then calls C# with no problems.

So, I guess my question becomes one of when the application domain is
created and when it is destroyed. Am I right in assuming that it gets
created when the managed C++ gets called (from the unmanaged C++), and
is destroyed when the managed C++ returns (to the unmanaged C++)?
 
W

Willy Denoyette [MVP]

Willy, thanks for the info. I'm afraid my poor explanation is causing
some misunderstanding. I have an unmanaged DLL that calls a managed
C++ DLL, but it doesn't do a LoadLibrary on it. (My unmanaged main
does a LoadLibrary on my unmanaged DLL; sorry about that.)

I assure you, though, that I am not using COM interop (at least, not
explicitly). I simply create the managed C++ DLL (and its associated
dll exports in a .h file, and a .lib file), and I compile my unmanaged
C++ against the .h file, and link my unmanaged C++ against the .lib.
Then, at runtime, when I call one of the managed C++ routines, the
system loads the managed runtime and calls my managed C++. I don't
call any COM functions in any of my DLLs. I've used COM before, and
I'm familiar with what's necessary to call COM objects/routines.

unmanaged main
LoadLibrary of unmanaged C++ DLL
Call routine in just loaded unmanaged C++ DLL
call to managed C++ (simple call)
call to various C# routines

BTW, my managed C++ then calls C# with no problems.

So, I guess my question becomes one of when the application domain is
created and when it is destroyed. Am I right in assuming that it gets
created when the managed C++ gets called (from the unmanaged C++), and
is destroyed when the managed C++ returns (to the unmanaged C++)?

Ok, I see you play the exports trick :), so you are building a mixed mode
assembly and an import library from your managed C++ code file.

Your managed C++ DLL shares a common interface (your .h file) with another
unmanaged code DLL, let's call them resp. Man.dll and UnMan.dll. Man.dll
exports some function(s)(or class method?) so a .lib (import library) is
created when built. Your UnMan.dll link step used this .lib to import the
functions you call from Man.dll. The OS loader will, when loading UnMan.dll
(dynamically) implicitly load Man.dll, and as it's a mixed mode dll, call
it's DllMain() who loads mscoree.dll as part of it's initialization.
When you run and first call into managed code, the EE (in mscoree.dll) loads
and initializes the CLR who creates a number of Application Domains, one of
them, the "Default domain", is the one used to load your managed classes and
is the sole AD used by your (managed part of the) application. When the call
returns to unmanaged code land the CLR and the AD are not touched. Now, as
it's not possible to unload the "Default Domain", your managed DLL will
remain attached and your classes loaded (and JITted).
If this is not what you wanted , you'll have to create another AD and load
your managed code into it.

Hope it helps.
Willy.
 
M

mflanagan

Ok, I see you play the exports trick :), so you are building a mixed mode
assembly and an import library from your managed C++ code file.

Your managed C++ DLL shares a common interface (your .h file) with another
unmanaged code DLL, let's call them resp. Man.dll and UnMan.dll. Man.dll
exports some function(s)(or class method?) so a .lib (import library) is
created when built. Your UnMan.dll link step used this .lib to import the
functions you call from Man.dll. The OS loader will, when loading UnMan.dll
(dynamically) implicitly load Man.dll, and as it's a mixed mode dll, call
it's DllMain() who loads mscoree.dll as part of it's initialization.
When you run and first call into managed code, the EE (in mscoree.dll) loads
and initializes the CLR who creates a number of Application Domains, one of
them, the "Default domain", is the one used to load your managed classes and
is the sole AD used by your (managed part of the) application. When the call
returns to unmanaged code land the CLR and the AD are not touched. Now, as
it's not possible to unload the "Default Domain", your managed DLL will
remain attached and your classes loaded (and JITted).
If this is not what you wanted , you'll have to create another AD and load
your managed code into it.

Hope it helps.
Willy.
Willy, yes, this helps a lot. I do have a question or two.

1. You refer to the "EE (in mscoree.dll)." What's the EE?

2. I'm unclear on unloading managed DLL (which you say doesn't happen
in the scenario I proposed). The main will explicitly unload my
unmanaged DLL. Are you saying that my managed DLL will remain loaded?
That's okay, I suppose. If that is the case, does that mean that, for
example, any class static members (in managed land) are still around?
And if I go in again (main Loads unman.dll and calls one of the
routines there, which calls a function in ManDll), any class
constructors will not be called again, correct?

3. I don't think I mentioned threading in my scenario (I didn't want
to make it even more confusing). Each call to the unMan.dll is made
from a separate thread. I'm handling any multi-thread problems,
except for those that might come about with static members. From what
you've said, the multiple threading doesn't affect my scenario any
more than it affects 'regular' .NET, yes? That is, if I want to
ensure that a class static data member is associated with a thread, I
can use the ThreadStaticAttribute, yes?

Thanks again for your help, WIlly.

Michael
 
W

Willy Denoyette [MVP]

Willy, yes, this helps a lot. I do have a question or two.

1. You refer to the "EE (in mscoree.dll)." What's the EE?

2. I'm unclear on unloading managed DLL (which you say doesn't happen
in the scenario I proposed). The main will explicitly unload my
unmanaged DLL. Are you saying that my managed DLL will remain loaded?
That's okay, I suppose. If that is the case, does that mean that, for
example, any class static members (in managed land) are still around?
And if I go in again (main Loads unman.dll and calls one of the
routines there, which calls a function in ManDll), any class
constructors will not be called again, correct?

3. I don't think I mentioned threading in my scenario (I didn't want
to make it even more confusing). Each call to the unMan.dll is made
from a separate thread. I'm handling any multi-thread problems,
except for those that might come about with static members. From what
you've said, the multiple threading doesn't affect my scenario any
more than it affects 'regular' .NET, yes? That is, if I want to
ensure that a class static data member is associated with a thread, I
can use the ThreadStaticAttribute, yes?

Thanks again for your help, WIlly.

Michael

Michael,
1. EE = Execution Engine, just a part of the CLR. The mscoree.dll presents
an interface that enables a Win32 process to host the EE (CLR).
2. When your Main unmaps (by calling FreeLibrary) the native DLL, your
managed dll's and your managed environment (AppDomains) aren't affected. The
"managed" static's are still around, and if your managed code runs in a
single AD, you should synchronize accesses to shared state from multiple
threads entering this AD (or try to eliminate shared state at all).
3. Yes, your scenario is similar to a regular .NET scenario, except that
your unmanaged code creates the threads that the CLR maps to thread objects
to run your managed code. The way you should threat your shared state
remains the same.

Willy.
 

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