I'm wetting my feet with dynamic code generation and System.Reflection.Emit
. All seems pretty easy and straightforward, but there's one question which I cannot find answered on the web.
When building dynamic assemblies with AssemblyBuilder
it's possible to create a type and then start using it immediately. If later you need to add another type to the assembly, you can do that too and it's all fine (as far as I can tell).
But what if there are two threads that are trying to build types for that assembly? Or what if one ready-made type is already being used, while another is in the making? Will there be any conflicts or race conditions?
Added: OK, I think that a bit more information is necessary.
What I'm doing with Reflection.Emit
is dynamically implementing interfaces at runtime. Basically I have something like:
class MagicClass
{
public static T GetImplementation<T>();
}
Where T
needs to be an interface (and a few other unrelated requirements).
Each interface will have exactly one implementation and that implementation will have exactly one instance. They will all be thread-safe singletons.
So when a request for a new, hitherto unseen interface comes in, I implement it, make an instance and then cache it for all eternity (which is here defined as "until my program is stopped").
This will however be done in a ASP.NET web application, so we have many threads requesting interfaces all the time. Performance is important and I'm trying to figure out how much multithreading I can afford.
It's pretty clear that a single interface will ever only be implemented by a single thread. But can I implement two different interfaces in two different threads at the same time? I guess the answer is - "better not".
OK, so I can add a lock that only one thread is doing an implementation at the same time. That will take care of builders interfering with each other. But what about those interfaces that were implemented previously? Other threads are using them at the same time while we're making a new one. I guess they're fine, unless they're trying to use some kind of reflection on their own assembly?
I could, of course, make one-assembly-per-interface-implementation policy, but that would spam the "Loaded Modules" debugger window real fast. Also, I don't know what performance effects there will be of having a 100 loaded assemblies (but I doubt that they will be good).
Added 2: Right, there must be something wrong with my language, since people don't seem to get it. Let me try with a code example:
var object1 = MagicClass.GetImplementation<I1>();
DoSomethingInAnotherThread(object1);
var object2 = MagicClass.GetImplementation<I2>();
Can there be a threading-related error between DoSomethingInAnotherThread(object1)
and MagicClass.GetImplementation<I2>()
?
We can assume that:
DoSomethingInAnotherThread(object1)
does NOT callMagicClass.GetImplementation<T>()
DoSomethingInAnotherThread(object1)
does NOT use reflection onobject1
and neither doesobject1
itself.
Basically, the question is - can an innocent call to object1.SomeMethod()
blow up because the assembly is being reorganized on another thread.
AssemblyBuilder
. This is how IronScheme is setup. From limited multi-threading tests, I have seen no issues popping up with this. I will try run some load tests for my web evaluator to confirm. – BriquetDuplicate type name within an assembly.
(thanks for letting me find a bug \o/) Will re-run after fix. Scheme code: gist.github.com/leppie/d0b3dc2ae20bd549463a – Briquet