WCF async during request and garbage collection - c#

I have a self hosted WCF service. It offers a processing function DoSth().
The processing might take long so I need to return OK to the caller prior
to finish the task. Currently I've implemented that by calling
Task.Factory.StartNew(() => DoWork());
Might it be possible that the garbage collector interferes so that the just created task may never finish?
If the program is self hosted, I would say that it does not interfere as long
as the host is running (static variables also remain their value).
Please correct me if I'm wrong.
But how would garbage collection react if the service is hosted in IIS?
If it interferes is there a way to prevent it?

The GC is never going to collect an object that might possibly be accessed by an executable code in the future (at least through any managed reference). That's how it is designed.
If there's any possible way for some code to execute that would use the object, then the GC isn't allowed to clean it up. It only cleans up objects that it can prove are never going to be accessed by any executable code ever again.
Since this task, the delegate it was given, and the objects used within the delegate can all be accessed by the thread that will be processing this request, they're all accessible, and are not eligible for collection.
Basically the only time you ever need to even consider the question of, "is the object I'm trying to use potentially going to end up cleaned up by the GC before I'm done with it" is when you're dealing with non-managed references, such as when using the WeakReference class or when interoping with other languages.

Related

Is there any way to work around OS loader lock deadlocks caused by third-party libraries?

I have an interesting problem that I haven't seen documented anywhere else (at least not this specific issue).
This issue is a combination of COM, VB6, and .NET and making them play nice.
Here's what I have:
A legacy VB6 ActiveX DLL (written by us)
A multi-threaded Windows service written in C# that processes requests from clients over the network and sends back results. It does this by creating a new STA thread to handle each request. Each request-handler thread instantiates a COM object (defined in the ActiveX DLL) to process the request and get the result (a string of XML is passed in, and it returns a string of XML back), explicitly releases the COM object, and exits. The service then sends the result back to the client.
All of the network code is handled using asynchronous networking (i.e. thread pool threads).
And yes, I know this is already a risky thing to be doing in the first place, since VB6 isn't very friendly with multi-threaded applications to begin with, but unfortunately it's what I am stuck with for the moment.
I've already fixed a number of things that were causing deadlocks in the code (for example, making sure the COM objects are actually created and called from a separate STA thread, making sure to explicitly release the COM objects before the thread exits to prevent deadlocks that were occurring between the garbage collector and the COM Interop code, etc.), but there is one deadlock scenario that I just can't seem to solve.
With some help from WinDbg, I was able to figure out what is happening, but I'm not sure how (or if) there is a way around this particular deadlock.
What's happening
If one request-handler thread is exiting, and another request-handler thread is starting at the same time, a deadlock can occur because of the way the VB6 runtime initialization and termination routines seem to work.
The deadlock occurs in the following scenario:
The new thread that is starting up is in the middle of creating a new instance of the (VB6) COM object to process an incoming request. At this point, the COM runtime is in the middle of a call to retrieve the object's class factory. The class factory implementation is in the VB6 runtime itself (MSVBVM60.dll). That is, its calling the VB6 runtime's DllGetClassObject function. This, in turn, calls an internal runtime function (MSVBVM60!CThreadPool::InitRuntime), which acquires a mutex and enters a critical section to do part of its work. At this point, it's about to call LoadLibrary to load oleaut32.dll into the process, while holding this mutex. So, now it's holding this internal VB6 runtime mutex and waiting for the OS loader lock.
The thread that is exiting is already running inside the loader lock, because it's done executing managed code and is executing inside the KERNEL32!ExitThread function. Specifically, it's in the middle of handling the DLL_THREAD_DETECH message for MSVBVM60.dll on that thread, which in turn calls a method to terminate the VB6 runtime on the thread (MSVBVM60!CThreadPool::TerminateRuntime). Now, this thread tries to acquire the same mutex that the other thread being initialized already has.
A classic deadlock. Thread A has L1 and wants L2, but Thread B has L2 and needs L1.
The problem (if you've followed me this far) is I don't have any control over what the VB6 runtime is doing in its internal thread initialization and teardown routines.
In theory, if I could force the VB6 runtime initialization code to run inside the OS loader lock, I would prevent the deadlock, because I am fairly certain the mutex the VB6 runtime is holding is specifically only used inside the initialization and termination routines.
Requirements
I can't make the COM calls from a single STA thread, because then the service won't be able to handle concurrent requests. I can't have a long-running request block other client requests either. This is why I create one STA thread per-request.
I need to create a new instance of the COM object on each thread, because I need to make sure each instance has its own copy of global variables in the VB6 code (VB6 gives each thread its own copy of all global variables).
Solutions I've tried that didn't work
Converted ActiveX DLL to ActiveX EXE
First, I tried the obvious solution and created an ActiveX EXE (out-of-process server) to handle the COM calls. Initially, I compiled it so that a new ActiveX EXE (process) was created for each incoming request, and I also tried it with the Thread Per Object compile option (one process instance is created, and it creates each object on a new thread within the ActiveX EXE).
This fixes the deadlock issue with respect to the VB6 runtime, because the VB6 runtime never gets loaded into the .NET code proper. However, this led to a different problem: if concurrent requests come into the service, the ActiveX EXE tends to fail randomly with RPC_E_SERVERFAULT errors. I assume this is because the COM marshalling and/or the VB6 runtime can't deal with concurrent object creation/destruction, or concurrent method calls, inside the ActiveX EXE.
Force the VB6 code to run inside the OS loader lock
Next, I switched back to using an ActiveX DLL for the COM class. To force the VB6 runtime to run its thread initialization code inside the OS loader lock, I created a native (Win32) C++ DLL, with code to handle DLL_THREAD_ATTACH in DllMain. The DLL_THREAD_ATTACH code calls CoInitialize and then instantiates a dummy VB6 class to force the VB6 runtime to be loaded and force the runtime initialization routine to run on the thread.
When the Windows service starts, I use LoadLibrary to load this C++ DLL into memory, so that any threads created by the service will execute that DLL's DLL_THREAD_ATTACH code.
The problem is that this code runs for every thread the service creates, including the .NET garbage collector thread and the thread-pool threads used by the async networking code, which doesn't end well (this just seems to cause the threads to never start properly, and I imagine initializing COM on the GC and thread-pool threads is in general just a very bad idea).
Addendum
I just realized why this is a bad idea (and probably part of the reason it didn't work): it isn't safe to call LoadLibrary when you are holding the loader lock. See Remarks section in this MSDN article: http://msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx, specifically:
Threads in DllMain hold the loader lock so no additional DLLs can be dynamically loaded or initialized.
Is there any way to workaround these issues?
So, my question is, is there any way to work around the original deadlock issue?
The only other thing I can think of is to create my own lock object and surround the code that instantiates the COM object in a .NET lock block, but then I have no way (that I know of) to put the same lock around the (operating system's) thread exit code.
Is there a more obvious solution to this issue, or am I plain out of luck here?
As long as all of your modules work in one process, you can hook Windows API by replacing some system calls with your wrappers. Then, you can wrap the calls in a single critical section to avoid deadlock.
There are several libraries and samples to achieve that, the technique is commonly known as detouring:
http://www.codeproject.com/Articles/30140/API-Hooking-with-MS-Detours
http://research.microsoft.com/en-us/projects/detours/
And of course the implementation of wrappers should be done in native code, preferably C++. .NET detours work too for high-level API functions such as MessageBox, but if you try to reimplement LoadLibrary API call in .NET then you may get a cyclic dependency issue because .NET runtime internally uses LoadLibrary function during execution and does this often.
So the solution looks like this to me: a separate .DLL module which is loaded at the very start of your application. The module fixes the deadlock problem by patching several VB and Windows API calls with your own wrappers. All wrappers do one thing: wrap the call in critical section and invoke the original API function to do the real job.
EDIT: in retrospect, I don't think this will work. The problem is that the deadlock can occur at any time that a Win32 thread exits, and since Win32 threads don't map 1:1 to .NET threads, we can't (within .NET) force Win32 threads to acquire the lock before exiting. In addition to the possibility of the .NET thread that is exiting being switched to a different OS thread, there are presumably OS threads not associated with any .NET thread (garbage collection and the like) which may start and exit at random.
The only other thing I can think of is to create my own lock object
and surround the code that instantiates the COM object in a .NET lock
block, but then I have no way (that I know of) to put the same lock
around the (operating system's) thread exit code.
That sounds like a promising approach. I gather from this that you
are able to modify the service's code, and you say each thread
explicitly releases the COM object before exiting, so presumably you
could claim a lock at this point, either just before explicitly
releasing the COM object or just after. The secret is to choose a
type of lock that is implicitly released once the thread holding it
has exited, such as a Win32 mutex.
It is likely that a Win32 mutex object does not become abandoned until
the thread has completed all DLL_THREAD_DETACH calls, although I don't
know whether this behaviour is documented. I'm not familiar with
locking in .NET but my guess is that they are unlikely to be suitable,
because even if the right kind of lock exists, it would be likely to
be considered abandoned as soon as the thread reaches the end of the
managed code section, i.e., before the calls to DLL_THREAD_DETACH.
If Win32 mutex objects don't do the trick (or if you very reasonably
prefer not to rely on undocumented behaviour) you might need to
implement the lock yourself. One way to do this would be to use
OpenThread to get a handle to the current thread and save this in your
lock object, along with an event or similar object. If the lock has
been claimed and you want to wait for it to be available, use
WaitForMultipleObjects to wait until either the thread handle or the
event is signaled. If the event is signaled this means the lock has
been explicitly released, if the thread handle is signaled it was
implicitly released by the thread exiting. Obviously implementing
this involves a lot of tricky details (for example: when a thread
explicitly releases the lock, you can't close the thread handle
because another thread might be waiting on it, so you'll have to close
it when the lock is next claimed instead) but it shouldn't be too
difficult to sort these out.
I don't see any reason why you couldn't load an extra instance of the ActiveX control in your startup code and just hang onto the reference. Presto, no more loader lock issues since the VB6 runtime never shuts down.
Since I'm still exploring my options, I wanted to still see if I could implement a solution in pure .NET code without using any native code, for the sake of simplicity. I'm not sure if this is a fool-proof solution yet, because I'm still trying to figure out whether it actually gives me the mutual exclusion I need, or if it just looks like it does.
Any thoughts or comments are welcome.
The relevant part of the code is below. Some notes:
The HandleRpcRequest method is called from a thread-pool thread when a new message is received from a remote client
This fires off a separate STA thread so that it can make the COM call safely
DbRequestProxy is a thin wrapper class around the real COM class I'm using
I used a ManualResetEvent (_safeForNewThread) to provide the mutual exclusion. The basic idea is that this event stays unsignaled (blocking other threads) if any one particular thread is about to exit (and hence potentially about to terminate the VB6 runtime). The event is only signaled again after the current thread completely terminates (after the Join call finishes). This way multiple request-handler threads can still execute concurrently unless an existing thread is exiting.
So far, I think this code is correct and guarantees that two threads can't deadlock in the VB6 runtime initialization/termination code anymore, while still allowing them to execute concurrently for most of their execution time, but I could be missing something here.
public class ClientHandler {
private static ManualResetEvent _safeForNewThread = new ManualResetEvent(true);
private void HandleRpcRequest(string request)
{
Thread rpcThread = new Thread(delegate()
{
DbRequestProxy dbRequest = null;
try
{
Thread.BeginThreadAffinity();
string response = null;
// Creates a COM object. The VB6 runtime initializes itself here.
// Other threads can be executing here at the same time without fear
// of a deadlock, because the VB6 runtime lock is re-entrant.
dbRequest = new DbRequestProxy();
// Call the COM object
response = dbRequest.ProcessDBRequest(request);
// Send response back to client
_messenger.Send(Messages.RpcResponse(response), true);
}
catch (Exception ex)
{
_messenger.Send(Messages.Error(ex.ToString()));
}
finally
{
if (dbRequest != null)
{
// Force release of COM objects and VB6 globals
// to prevent a different deadlock scenario with VB6
// and the .NET garbage collector/finalizer threads
dbRequest.Dispose();
}
// Other request threads cannot start right now, because
// we're exiting this thread, which will detach the VB6 runtime
// when the underlying native thread exits
_safeForNewThread.Reset();
Thread.EndThreadAffinity();
}
});
// Make sure we can start a new thread (i.e. another thread
// isn't in the middle of exiting...)
_safeForNewThread.WaitOne();
// Put the thread into an STA, start it up, and wait for
// it to end. If other requests come in, they'll get picked
// up by other thread-pool threads, so we won't usually be blocking anyone
// by doing this (although we are blocking a thread-pool thread, so
// hopefully we don't block for *too* long).
rpcThread.SetApartmentState(ApartmentState.STA);
rpcThread.Start();
rpcThread.Join();
// Since we've joined the thread, we know at this point
// that any DLL_THREAD_DETACH notifications have been handled
// and that the underlying native thread has completely terminated.
// Hence, other threads can safely be started.
_safeForNewThread.Set();
}
}
I had written a rather complex code using VB6,VC6 about 20 years ago and I need to port it to visual studio.net.
I simply took the functions as I had written them along with the header files corrected all the compile errors (which were MANY) and then tried to load it. got "loaderlock closed"
I then decided to redo all the files starting from those that few other files depended upon and then worked my way up and as I went I included only the header files that that particular file required. The result it loads now just fine. no more loaderlock closed.
the lesson for me is don't include any more header files in a particular cpp file than is absolutely necessary.
hope this helps
from a very happy camper!!
david

Why classes with finalizers need more than one garbage collection cycle?

This article says
If an object has a finalizer, it is not immediately removed when the
garbage collector decides it is no longer ‘live’. Instead, it becomes
a special kind of root until .NET has called the finalizer method.
This means that these objects usually require more than one garbage
collection to be removed from memory, as they will survive the first
time they are found to be unused.
My question is why GC don't call finalizer when it finds that object can't be referenced anymore and collect the object right away? why does it need more than on garbage collection?
Two points to consider:
The finalizer may take some time to complete. For example, it may end up closing a resource or something similar. You wouldn't want that to be part of the garbage collection time, which may be blocking threads from doing work (when they just want to get some memory). By running finalization separately, the GC itself can complete very quickly, and the finalization work can be done in parallel with other work later.
The finalizer may resurrect the object by making it visible again - but detecting that would (I suspect) require another sweep of memory anyway... so why not just wait until the next time it was going to happen?
Because (depending on the GC mode selected) when it is performing GC it has to pause key parts of the runtime. Hence you want this to be as quick as is possible. This creates two issues:
it doesn't know how long the finalizer will take to run (although it has a hard limit), and doesn't want to delay resuming the runtime
the runtime needs to be running for the finalizer to work reliably (even if a GC thread is used, the code you write could conceivably care about other threads)
To address both issues, those with pending finalizers are queued, and then executed after the GC has finished (when the runtime is working).
As a side-note, it is a good practice to combine finalizers with IDisposable and have the Dispose() cancel the finalization; that way it doesn't need finalization later, and is cleaned up in one step.
When the .net garbage-collector runs, objects are divided into three categories: objects which are reachable from a "normal" rooted reference, objects which are not reachable by any rooted reference, and objects which are not reachable by any "normal" rooted reference, but have either requested to receive notification when they are abandoned, or are reachable from other objects that have done so. The garbage collector makes a list of objects in that third category; that list is stored as a rooted reference, making all objects in it 'live'. The system goes through items in that list, though, cancels their 'notification' requests, runs their Finalize() method, and removes them from the list. If no reference to the object exists anywhere once all that is said and done, then the object will be declared "dead" on the next GC cycle.

Garbage collection Guarantees

What guarantees are the for the garbage collector?
From my research I have managed to find:
If there is still a reference to the memory it will not be garbage collected
If there is no reference:
When it is GC is non deterministic
When the GC kicks in the finalizer will be run before memory is released.
There is no guarantee about the order of Finalizers (so do not assume parent will be run before child).
But what I really want to know is:
Is there a guarantee that all memory will eventually be garbage collected and the finalizer (destructor) run on the object (assuming the program exited nicely). For example an application with no memory pressure when it eventually exits will it force the GC to go find all objects and make sure the finalizer (destructor) is called (including static member variables)?
I did find a quote on this page:
http://www.c-sharpcorner.com/UploadFile/tkagarwal/MemoryManagementInNet11232005064832AM/MemoryManagementInNet.aspx
In addition, by default, Finalize methods are not called for unreachable objects when an application exits so that the application may terminate quickly.
But I am not sure how authoritative this quote is.
I also found documentation on:
CriticalFinalizerObject
Is there a guarantee that all memory
will eventually be garbage collected
and the finalizer (destructor) run on
the object (assuming the program
exited nicely).
No. From the Object.Finalize documentation it is clear that finalizers may not be invoked if
Some other finalizers don't finish properly:
Another finalizer blocks indefinitely
(goes into an infinite loop, tries to
obtain a lock it can never obtain and
so on). Because the runtime attempts
to run finalizers to completion, other
finalizers might not be called if a
finalizer blocks indefinitely.
Some other finalizers create more
finalizable objects, making it
impossible to finalize all
finalizable objects:
The runtime continues to Finalize
objects during shutdown only while the
number of finalizable objects
continues to decrease.
Some other finalizers throw exceptions:
If Finalize or an override of Finalize
throws an exception, and the runtime
is not hosted by an application that
overrides the default policy, the
runtime terminates the process and no
active try-finally blocks or
finalizers are executed. This behavior
ensures process integrity if the
finalizer cannot free or destroy
resources.
That being said, there are more reasons why you wouldn't want to use finalizers unless strictly necessary.
They slow down the garbage collector
(even making it possible to slow it
down so much that memory is not
reclaimed as fast as it is used up).
They run on another thread, bringing
multi-threading issues into play.
They're not executed in a
deterministic order.
They can resurrect objects which were
already finalized (and which won't be
finalized again unless explicitly
re-registered for finalization).
The only time you should write a finalizer is when you are building a type to handle a new kind of unmanaged resource. For example, a data access layer that uses Sql Server in a business app doesn't need a finalizer anywhere, even though there are unmanaged database connections involved, because the basic SqlConnection class will already finalize those connections if needed. But if you're building a brand new database engine from scratch that has connection limits similar to sql server's and are implementing the ado.net provider for it, that connection type should implement a finalizer to be as sure as possible that your connections are released.
But you don't get any guarantees beyond what happens when a process ends.
Update:
Given this context:
I am having a discussion with a collegue over a code review I did of his code. He insists that the destructor is guranteed to be called on an object. I disagree (but am not sure) and would prefer the use of IDisposable.
You are right to criticize the use of a destructor/finalizer. As I said above, you should only use them when working with an unmanaged resource that is genuinely new. Not just that instance of the resource, but the kind of resource you are working with.
For code that wraps "normal" unmanaged resources (things like SqlConnection, TcpClient, etc), IDisposable is a better choice. Then you know the resource will be cleaned up as soon as Dispose() is called rather than needing to wait for the type to be collected. If no one calls Dispose() (which is likely your colleague's concern), by the time your new type can be collected the instance of the original type for the unmanaged resource you are wrapping should be able to be collected as well, and it's finalizer will release the resource.
The main thing you need to bring to the table is that the finalizer cannot be called until the object is collected. You have to wait on the garbage collector, meaning you may be holding the resource open even longer. IDisposable allows you to release it right away. Of course you could do both, but that doesn't sound like what's going on here, and if you do have both you have to be careful not to conflict with the original type's finalizer or you could cause unwanted and harmful exceptions. And really, your own finalizer implementation is just redundant here and adds needless complexity.
Finally, I have to take issue with this statement:
If there is still a reference to the memory it will not be garbage collected
There can be references to an object and it will still be collected. What matters is if the object is reachable: are any of the references to the object rooted. For example, you may have a list with several objects in it. The list goes out of scope. Obviously there is still a reference to all of the objects in the list, but they can still all be collected in the first pass of the GC because the reference is no longer rooted.
1.6.7.6 of the Spec says:
1.6.7.6 Destructors
A destructor is a member that implements the actions
required to destruct an instance of a
class. Destructors cannot have
parameters, they cannot have
accessibility modifiers, and they
cannot be invoked explicitly. The
destructor for an instance is invoked
automatically during garbage
collection.
The garbage collector is
allowed wide latitude in deciding when
to collect objects and run
destructors. Specifically, the timing
of destructor invocations is not
deterministic, and destructors may be
executed on any thread. For these and
other reasons, classes should
implement destructors only when no
other solutions are feasible.
The
using statement provides a better
approach to object destruction.
So no, it's not guaranteed they are called.
The only time that a finalizer won't be invoked at all is if an AppDomain is forcibly unloaded.
In general, you don't need to worry about it.
There is no guarantee.
There might be a guarantee if your process terminates nicely for some definition of nicely. But there are so many things not nice that can happen:
power failure
process terminated in a 'hard' or 'forced' way
unmanaged thread throwing calling OS exit() function or throwing an exception
call to System.Environment.FailFast, which does:
MSDN: "Terminates a process but does not execute any active try-finally blocks or finalizers."

Should one always keep a reference to a running Thread object in C#?

Or is it okay to do something like this:
new Thread( new ThreadStart( delegate { DoSomething(); } ) ).Start();
?
I seem to recall that under such a scenario, the Thread object would be garbage collected, but the underlying OS thread would continue to run until the end of the delegate passed into it. I'm basically looking for ThreadPool functionality, but don't want the threads to be background threads (i.e. I want them to keep the app alive).
Update:
According to Jason, the CLR actually keeps an internal reference to the Thread object, while running, so it won't be garbage collected until the thread exits.
I have generally found that if I need to directly start a new thread the way you are in your example, rather than grabbing one from the thread pool, then it is a long running thread and I will need a reference to it later to kill it, monitor it, etc. For short run threads like invoking IO on a background thread, etc, I always use a thread pool thread (usually indirectly through a someDelete.BeginBlah(...) method call). When using a thread pool thread like this I prefer to NOT keep a reference around. I don't know if another programmer might inappropriately use a reference to that thread. If I don't need a reference, I don't keep it around to clutter up code.
Edit: To answer your edit about threads being garbage collected, this will not occur while the thread is running. The CLR keeps a reference to every running thread. The object representing the thread will NOT be collected.
It depends. In the situation where the user can cancel the operation of your thread, you should keep the reference so the thread can be canceled when the user want. In other situations, there may be no need to store the reference.
I have had a number of cases in production code where doing this has been appropriate. So, yes defining and starting a thread in one line without retaining a reference has it's place. I think keeping a reference "just in case" you redesign later and need it is failing the principle of creating the simplest thing that works.
And, to the second part, no it will not be GC'd while it is running; threads are root level objects from which the GCtor will chase down references. The Thread instance will only be GCd once it is no longer reachable by any running thread including the one which you start on it.
And beware leaking Thread instances which are created but never started. I believe they will hang around forever.
It might be good to ask the question "How often can this thread be started up?" Is it per-application, per-class, per-object instance, or per-method invocation? This may tell you what kind of variable (if any) to store it in.
Yes, you should, because you never know when you will have to change the code later to handle the thread in some way. That, and putting too much stuff on one line like that is just ugly.
So truthfully, you can do it your way, so the answer really comes down to code style preference.
In addition to what "m3rLinEz" has posted above, another draw back is that if any exception occurs in your thread it will be hard to even detect such cases.

lock keyword in C#

I understand the main function of the lock key word from MSDN
lock Statement (C# Reference)
The lock keyword marks a statement
block as a critical section by
obtaining the mutual-exclusion lock
for a given object, executing a
statement, and then releasing the
lock.
When should the lock be used?
For instance it makes sense with multi-threaded applications because it protects the data. But is it necessary when the application does not spin off any other threads?
Is there performance issues with using lock?
I have just inherited an application that is using lock everywhere, and it is single threaded and I want to know should I leave them in, are they even necessary?
Please note this is more of a general knowledge question, the application speed is fine, I want to know if that is a good design pattern to follow in the future or should this be avoided unless absolutely needed.
When should the lock be used?
A lock should be used to protect shared resources in multithreaded code. Not for anything else.
But is it necessary when the application does not spin off any other threads?
Absolutely not. It's just a time waster. However do be sure that you're not implicitly using system threads. For example if you use asynchronous I/O you may receive callbacks from a random thread, not your original thread.
Is there performance issues with using lock?
Yes. They're not very big in a single-threaded application, but why make calls you don't need?
...if that is a good design pattern to follow in the future[?]
Locking everything willy-nilly is a terrible design pattern. If your code is cluttered with random locking and then you do decide to use a background thread for some work, you're likely to run into deadlocks. Sharing a resource between multiple threads requires careful design, and the more you can isolate the tricky part, the better.
All the answers here seem right: locks' usefulness is to block threads from acessing locked code concurrently. However, there are many subtleties in this field, one of which is that locked blocks of code are automatically marked as critical regions by the Common Language Runtime.
The effect of code being marked as critical is that, if the entire region cannot be entirely executed, the runtime may consider that your entire Application Domain is potentially jeopardized and, therefore, unload it from memory. To quote MSDN:
For example, consider a task that attempts to allocate memory while holding a lock. If the memory allocation fails, aborting the current task is not sufficient to ensure stability of the AppDomain, because there can be other tasks in the domain waiting for the same lock. If the current task is terminated, other tasks could be deadlocked.
Therefore, even though your application is single-threaded, this may be a hazard for you. Consider that one method in a locked block throws an exception that is eventually not handled within the block. Even if the exception is dealt as it bubbles up through the call stack, your critical region of code didn't finish normally. And who knows how the CLR will react?
For more info, read this article on the perils of Thread.Abort().
Bear in mind that there might be reasons why your application is not as single-threaded as you think. Async I/O in .NET may well call-back on a pool thread, for example, as do some of the various timer classes (not the Windows Forms Timer, though).
Generally speaking if your application is single threaded, you're not going to get much use out of the lock statement. Not knowing your application exactly, I don't know if they're useful or not - but I suspect not. Further, if you're application is using lock everywhere I don't know that I would feel all that confident about it working in a multi-threaded environment anyways - did the original developer actually know how to develop multi-threaded code, or did they just add lock statements everywhere in the vague hope that that would do the trick?
lock should be used around the code that modifies shared state, state that is modified by other threads concurrently, and those other treads must take the same lock.
A lock is actually a memory access serializer, the threads (that take the lock) will wait on the lock to enter until the current thread exits the lock, so memory access is serialized.
To answer you question lock is not needed in a single threaded application, and it does have performance side effects. because locks in C# are based on kernel sync objects and every lock you take creates a transition to kernel mode from user mode.
If you're interested in multithreading performance a good place to start is MSDN threading guidelines
You can have performance issues with locking variables, but normally, you'd construct your code to minimize the lengths of time that are spent inside a 'locked' block of code.
As far as removing the locks. It'll depend on what exactly the code is doing. Even though it's single threaded, if your object is implemented as a Singleton, it's possible that you'll have multiple clients using an instance of it (in memory, on a server) at the same time..
Yes, there will be some performance penalty when using lock but it is generally neglible enough to not matter.
Using locks (or any other mutual-exclusion statement or construct) is generally only needed in multi-threaded scenarios where multiple threads (either of your own making or from your caller) have the opportunity to interact with the object and change the underlying state or data maintained. For example, if you have a collection that can be accessed by multiple threads you don't want one thread changing the contents of that collection by removing an item while another thread is trying to read it.
Lock(token) is only used to mark one or more blocks of code that should not run simultaneously in multiple threads. If your application is single-threaded, it's protecting against a condition that can't exist.
And locking does invoke a performance hit, adding instructions to check for simultaneous access before code is executed. It should only be used where necessary.
See the question about 'Mutex' in C#. And then look at these two questions regarding use of the 'lock(Object)' statement specifically.
There is no point in having locks in the app if there is only one thread and yes, it is a performance hit although it does take a fair number of calls for that hit to stack up into something significant.

Categories

Resources