On Fri, 28 Dec 2007 12:01:41 -0800, Paul Schwann <pa**********@gmail.com
wrote:
Hi Peter,
thanks a lot for your detailed answer. I appreciate it a lot! I am
aware of the fact that the request I have is somewhat unusal. This is
due to the implementation of the underlying library which will be
called by all of those A, B, C... methods I mentioned.
The situation is such that this library is not thread safe in any way.
Thus, only one thread shall access it at at time.
There are other ways to accomplish that. Better ones, IMHO.
On the other hand we have those A, B, C methods which belong to
different parts of the application and do different things of course.
Nevertheless, they all access this library sooner or later.
It's true that serializing the calls to those methods will ensure
synchronization of access to the library. However, your description
implies that accessing the library isn't _all_ that those methods are
doing, and so of course if you serialize the methods you fail to take
advantage of any parallelism that might otherwise exist between the
methods (e.g. if two or more are doing i/o, or if you have a computer
system with more than one CPU core).
It would be simplest if you could simply add the synchronization to the
methods being called. However, I understand that it's possible those
methods might have numerous calls to the library written into the code and
it would be tedious and error-prone to try to synchronize each and every
call. If that's the case, then the better alternative would be to modify
the library so that it's thread-safe. Assuming that you don't have
control over the library itself, the way to do this would be to create a
wrapper class that accesses the library, and which includes the
synchronizing code itself, locking around each call into the library.
By the way, by "synchronizing" I just mean any mechanism available in .NET
for accomplishing this. A very common scenario is to create a plain
"object" type instance (e.g. "object _objLock = new object()") and use
that as the parameter for a "lock()" statement, with the call to the
library inside the block protected by the lock.
[...]
About my little code snippet: Of cousre, reading/writing of this
List<must be thread safe. Thus, my idea is that in a synchronized
part of the code, the list is copied and this copy is used for the
enumaration.
Thus, the original List<can be manipulated at any time except for
the very short time period required to create the copy.
Once a method is removed or added to the List<>, it will executed the
NEXT time the for.. loop runs. It has no impact on the current loop-
run. This behavior is exceptable for my application.
I don't understand. If that behavior is acceptable for the application,
then why not just have a ThreadStart delegate that can be modified by code
wanting to add or remove these methods, and then use that delegate when
you start the thread? This would be a variation on the implementation Jon
suggests, except that instead of creating the delegate in the method that
starts the thread, you'd keep the delegate variable somewhere more
accessible to the code that wants to add or remove methods.
Delegates are already immutable and behave pretty much like what you've
suggested above (a new copy is made each time something's added or
removed, with just the reference being replaced) so if you just provide a
method to lock around the changes to the delegate, you'll be assured that
when you go to use the delegate it's in a usable state and won't change
during the execution of the thread itself.
Of course, this is very similar to what an event does, and you may find
that it works even better to define the delegate variable as an event, and
pass a copy of that event variable as the ThreadStart delegate. For
example:
event ThreadStart LibraryAccess;
void Start()
{
Thread thread = new Thread(LibraryAccess);
thread.Start();
}
Then you'd just use syntax like this:
LibraryAccess += A;
LibraryAcdess += B;
LibraryAccess -= A;
// etc.
To add and remove the methods. Each time the thread is created, it would
get the current copy of the event as a ThreadStart delegate and use that
to execute the thread.
Of course, if you are running these methods on a relatively frequent
basis, it may make sense to use the thread pool rather than creating a new
thread each time. But I think if they only get run every couple of
seconds and the execution itself isn't extremely brief, creating a
dedicated thread is probably okay.
Of course, all of this latter discussion assumes that you cannot make the
library thread-safe and must serialize the execution of these methods. As
I mentioned above, I think a better approach would be in fact to not
serialize the execution of the methods (possibly using the thread pool to
execute them) and make the library thread-safe somehow, even if that means
writing a whole new class that wraps the library and synchronizes access
to it for you.
Pete