My objective is a convention for thread-safe functionality and exception handling within my application. I'm relatively new to the concept of thread management/multithreading. I am using .NET 3.5
I wrote the following helper method to wrap all my locked actions after reading this article http://blogs.msdn.com/b/ericlippert/archive/2009/03/06/locks-and-exceptions-do-not-mix.aspx, which was linked in response to this question, Monitor vs lock.
My thought is that if I use this convention consistently in my application, it will be easier to write thread-safe code and to handle errors within thread safe code without corrupting the state.
public static class Locking
{
private static readonly Dictionary<object,bool> CorruptionStateDictionary = new Dictionary<object, bool>();
private static readonly object CorruptionLock = new object();
public static bool TryLockedAction(object lockObject, Action action, out Exception exception)
{
if (IsCorrupt(lockObject))
{
exception = new LockingException("Cannot execute locked action on a corrupt object.");
return false;
}
exception = null;
Monitor.Enter(lockObject);
try
{
action.Invoke();
}
catch (Exception ex)
{
exception = ex;
}
finally
{
lock (CorruptionLock) // I don't want to release the lockObject until its corruption-state is updated.
// As long as the calling class locks the lockObject via TryLockedAction(), this should work
{
Monitor.Exit(lockObject);
if (exception != null)
{
if (CorruptionStateDictionary.ContainsKey(lockObject))
{
CorruptionStateDictionary[lockObject] = true;
}
else
{
CorruptionStateDictionary.Add(lockObject, true);
}
}
}
}
return exception == null;
}
public static void Uncorrupt(object corruptLockObject)
{
if (IsCorrupt(corruptLockObject))
{
lock (CorruptionLock)
{
CorruptionStateDictionary[corruptLockObject] = false;
}
}
else
{
if(!CorruptionStateDictionary.ContainsKey(corruptLockObject))
{
throw new LockingException("Uncorrupt() is not valid on object that have not been corrupted.");
}
else
{
// The object has previously been uncorrupted.
// My thought is to ignore the call.
}
}
}
public static bool IsCorrupt(object lockObject)
{
lock(CorruptionLock)
{
return CorruptionStateDictionary.ContainsKey(lockObject) && CorruptionStateDictionary[lockObject];
}
}
}
I use a LockingException class for ease of debugging.
public class LockingException : Exception
{
public LockingException(string message) : base(message) { }
}
Here is an example usage class to show how I intend to use this.
public class ExampleUsage
{
private readonly object ExampleLock = new object();
public void ExecuteLockedMethod()
{
Exception exception;
bool valid = Locking.TryLockedAction(ExampleLock, ExecuteMethod, out exception);
if (!valid)
{
bool revalidated = EnsureValidState();
if (revalidated)
{
Locking.Uncorrupt(ExampleLock);
}
}
}
private void ExecuteMethod()
{
//does something, maybe throws an exception
}
public bool EnsureValidState()
{
// code to make sure the state is valid
// if there is an exception returns false,
return true;
}
}
Your solution seems to add nothing but complexity due to a race in the TryLockedAction:
if (IsCorrupt(lockObject))
{
exception = new LockingException("Cannot execute locked action on a corrupt object.");
return false;
}
exception = null;
Monitor.Enter(lockObject);
The lockObject might become "corrupted" while we are still waiting on the Monitor.Enter, so there is no protection.
I'm not sure what behaviour you'd like to achieve, but probably it would help to separate locking and state managing:
class StateManager
{
public bool IsCorrupted
{
get;
set;
}
public void Execute(Action body, Func fixState)
{
if (this.IsCorrupted)
{
// use some Exception-derived class here.
throw new Exception("Cannot execute action on a corrupted object.");
}
try
{
body();
}
catch (Exception)
{
this.IsCorrupted = true;
if (fixState())
{
this.IsCorrupted = false;
}
throw;
}
}
}
public class ExampleUsage
{
private readonly object ExampleLock = new object();
private readonly StateManager stateManager = new StateManager();
public void ExecuteLockedMethod()
{
lock (ExampleLock)
{
stateManager.Execute(ExecuteMethod, EnsureValidState);
}
}
private void ExecuteMethod()
{
//does something, maybe throws an exception
}
public bool EnsureValidState()
{
// code to make sure the state is valid
// if there is an exception returns false,
return true;
}
}
Also, as far as I understand, the point of the article is that state management is harder in presence of concurrency. However, it's still just your object state correctness issue which is orthogonal to the locking and probably you need to use completely different approach to ensuring correctness. E.g. instead of changing some complex state withing locked code region, create a new one and if it succeeded, just switch to the new state in a single and simple reference assignment:
public class ExampleUsage
{
private ExampleUsageState state = new ExampleUsageState();
public void ExecuteLockedMethod()
{
var newState = this.state.ExecuteMethod();
this.state = newState;
}
}
public class ExampleUsageState
{
public ExampleUsageState ExecuteMethod()
{
//does something, maybe throws an exception
}
}
Personally, I always tend to think that manual locking is hard-enough to treat each case when you need it individually (so there is no much need in generic state-management solutions) and low-lelvel-enough tool to use it really sparingly.
Though it looks reliable, I have three concerns:
1) The performance cost of Invoke() on every locked action could be severe.
2) What if the action (the method) requires parameters? A more complex solution will be necessary.
3) Does the CorruptionStateDictionary grow endlessly? I think the uncorrupt() method should problem remove the object rather than set the data false.
Move the IsCorrupt test and the Monitor.Enter inside
the Try
Move the corruption set
handling out of finally and into the Catch block (this should
only execute if an exception has
been thrown)
Don't release the primary lock until after the
corruption flag has been set (leave
it in the finaly block)
Don't restrict the execption to the calling thread; either rethow
it or add it to the coruption
dictionary by replacing the bool
with the custom execption, and
return it with the IsCorrupt Check
For Uncorrupt simply remove the
item
There are some issues with the locking sequencing (see below)
That should cover all the bases
public static class Locking
{
private static readonly Dictionary<object, Exception> CorruptionStateDictionary = new Dictionary<object, Exception>();
private static readonly object CorruptionLock = new object();
public static bool TryLockedAction(object lockObject, Action action, out Exception exception)
{
var lockTaken = false;
exception = null;
try
{
Monitor.Enter(lockObject, ref lockTaken);
if (IsCorrupt(lockObject))
{
exception = new LockingException("Cannot execute locked action on a corrupt object.");
return false;
}
action.Invoke();
}
catch (Exception ex)
{
var corruptionLockTaken = false;
exception = ex;
try
{
Monitor.Enter(CorruptionLock, ref corruptionLockTaken);
if (CorruptionStateDictionary.ContainsKey(lockObject))
{
CorruptionStateDictionary[lockObject] = ex;
}
else
{
CorruptionStateDictionary.Add(lockObject, ex);
}
}
finally
{
if (corruptionLockTaken)
{
Monitor.Exit(CorruptionLock);
}
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(lockObject);
}
}
return exception == null;
}
public static void Uncorrupt(object corruptLockObject)
{
var lockTaken = false;
try
{
Monitor.Enter(CorruptionLock, ref lockTaken);
if (IsCorrupt(corruptLockObject))
{
{ CorruptionStateDictionary.Remove(corruptLockObject); }
}
}
finally
{
if (lockTaken)
{
Monitor.Exit(CorruptionLock);
}
}
}
public static bool IsCorrupt(object lockObject)
{
Exception ex = null;
return IsCorrupt(lockObject, out ex);
}
public static bool IsCorrupt(object lockObject, out Exception ex)
{
var lockTaken = false;
ex = null;
try
{
Monitor.Enter(CorruptionLock, ref lockTaken);
if (CorruptionStateDictionary.ContainsKey(lockObject))
{
ex = CorruptionStateDictionary[lockObject];
}
return CorruptionStateDictionary.ContainsKey(lockObject);
}
finally
{
if (lockTaken)
{
Monitor.Exit(CorruptionLock);
}
}
}
}
The approach I would suggest would be to have a lock-state-manager object, with an "inDangerState" field. An application that needs to access a protected resource starts by using the lock-manager-object to acquire the lock; the manager will acquire the lock on behalf of the application and check the inDangerState flag. If it's set, the manager will throw an exception and release the lock while unwinding the stack. Otherwise the manager will return an IDisposable to the application which will release the lock on Dispose, but which can also manipulate the danger state flag. Before putting the locked resource into a bad state, one should call a method on the IDisposable which will set inDangerState and return a token that can be used to re-clear it once the locked resource is restored to a safe state. If the IDisposable is Dispose'd before the inDangerState flag is re-cleared, the resource will be 'stuck' in 'danger' state.
An exception handler which can restore the locked resource to a safe state should use the token to clear the inDangerState flag before returning or propagating the exception. If the exception handler cannot restore the locked resource to a safe state, it should propagate the exception while inDangerState is set.
That pattern seems simpler than what you suggest, but seems much better than assuming either that all exceptions will corrupt the locked resource, or that none will.
Related
Suppose I have a Singleton that loads resources into memory when created, and performs operation on the data when callings its methods.
Now suppose, that I want to have the ability to tell the Singleton to release those resources, as I don't expect to be using them in the near future, but also be able to load those resources back in, when the time comes. And I want it all to be thread safe.
What would be the best way to aproach this problem?
Would this example work?:
// Singleton implementation
...
private IDisposable resource;
private bool loadingResources;
private IDisposable Resource {
get => resource ?? throw new CustomException();
}
// Method A
public void A() {
var resource = Resource; // Throws CustomException if resource is null
// Do stuff
}
// Method B
public void B() {
var resource = Resource;
// Do stuff
}
public void ReleaseResources() {
if (resource != null)
lock (thislock) {
//resource.Dispose();
resource = null;
}
}
public void LoadResources() {
if (!loadingResources && resource == null)
lock (thislock)
if (!loadingResources && resource == null)
{
loadingResources = true;
// Load resources
resource = CreateResource();
loadingResources = false;
}
}
I would suggest separating the resource handling from the actual usage. Assuming the resource requires disposal this could look something like:
public class DisposableWrapper<T> where T : IDisposable
{
private readonly Func<T> resourceFactory;
private T resource;
private bool constructed;
private object lockObj = new object();
private int currentUsers = 0;
public DisposableWrapper(Func<T> resourceFactory)
{
this.resourceFactory = resourceFactory;
}
public O Run<O>(Func<T, O> func)
{
lock (lockObj)
{
if (!constructed)
{
resource = resourceFactory();
constructed = true;
}
currentUsers++;
}
try
{
return func(resource);
}
catch
{
return default;
}
finally
{
Interlocked.Decrement(ref currentUsers);
}
}
public void Run(Action<T> action)
{
lock (lockObj)
{
if (!constructed)
{
resource = resourceFactory();
constructed = true;
}
currentUsers++;
}
try
{
action(resource);
}
finally
{
Interlocked.Decrement(ref currentUsers);
}
}
public bool TryRelease()
{
lock (lockObj)
{
if (currentUsers == 0 && constructed)
{
constructed = false;
resource.Dispose();
resource = default;
return true;
}
return false;
}
}
}
If the resource does not require disposal I would suggest to instead use lazy<T>. Releasing resources would simply mean replacing the existing lazy object with a new one. Letting the old object be cleaned up by the garbage collector.
I have the following base code. The ActionMonitor can be used by anyone, in whatever setting, regardless of single-thread or multi-thread.
using System;
public class ActionMonitor
{
public ActionMonitor()
{
}
private object _lockObj = new object();
public void OnActionEnded()
{
lock (_lockObj)
{
IsInAction = false;
foreach (var trigger in _triggers)
trigger();
_triggers.Clear();
}
}
public void OnActionStarted()
{
IsInAction = true;
}
private ISet<Action> _triggers = new HashSet<Action>();
public void ExecuteAfterAction(Action action)
{
lock (_lockObj)
{
if (IsInAction)
_triggers.Add(action);
else
action();
}
}
public bool IsInAction
{
get;private set;
}
}
On exactly one occasion, when I examined a crash on client's machine, an exception was thrown at:
System.Core: System.InvalidOperationException Collection was modified;enumeration operation may not execute. at
System.Collections.Generic.HashSet`1.Enumerator.MoveNext() at
WPFApplication.ActionMonitor.OnActionEnded()
My reaction when seeing this stack trace: this is unbelievable! This must be a .Net bug!.
Because although ActionMonitor can be used in multithreading setting, but the crash above shouldn't occur-- all the _triggers ( the collection) modification happens inside a lock statement. This guarantees that one cannot iterate over the collection and modifying it at the same time.
And, if _triggers happened to contain an Action that involves ActionMonitor, then the we might get a deadlock, but it would never crash.
I have seen this crash exactly once, so I can't reproduce the problem at all. But base on my understanding of multithreading and lock statement, this exception can never have occurred.
Do I miss something here? Or is it known that .Net can behave it a very quirky way, when it involves System.Action?
You didn't shield your code against the following call:
private static ActionMonitor _actionMonitor;
static void Main(string[] args)
{
_actionMonitor = new ActionMonitor();
_actionMonitor.OnActionStarted();
_actionMonitor.ExecuteAfterAction(Foo1);
_actionMonitor.ExecuteAfterAction(Foo2);
_actionMonitor.OnActionEnded();
Console.ReadLine();
}
private static void Foo1()
{
_actionMonitor.OnActionStarted();
//Notice that if you would call _actionMonitor.OnActionEnded(); here instead of _actionMonitor.OnActionStarted(); - you would get a StackOverflow Exception
_actionMonitor.ExecuteAfterAction(Foo3);
}
private static void Foo2()
{
}
private static void Foo3()
{
}
FYI - that's the scenario Damien_The_Unbeliever is talking about in the comments.
To fix that issue the only 2 things that come in mind are
Don't call it like this, it's your class and your code is calling it so make sure you stick to your own rules
Get a copy of the _trigger list and enumarate this
About point 1, you could track if OnActionEnded is running and throw an exception if OnActionStarted is called while running:
private bool _isRunning = false;
public void OnActionEnded()
{
lock (_lockObj)
{
try
{
_isRunning = true;
IsInAction = false;
foreach (var trigger in _triggers)
trigger();
_triggers.Clear();
}
finally
{
_isRunning = false;
}
}
}
public void OnActionStarted()
{
lock (_lockObj)
{
if (_isRunning)
throw new NotSupportedException();
IsInAction = true;
}
}
About point 2, how about this
public class ActionMonitor
{
public ActionMonitor()
{
}
private object _lockObj = new object();
public void OnActionEnded()
{
lock (_lockObj)
{
IsInAction = false;
var tmpTriggers = _triggers;
_triggers = new HashSet<Action>();
foreach (var trigger in tmpTriggers)
trigger();
//have to decide what to do if _triggers isn't empty here, we could use a while loop till its empty
//so for example
while (true)
{
var tmpTriggers = _triggers;
_triggers = new HashSet<Action>();
if (tmpTriggers.Count == 0)
break;
foreach (var trigger in tmpTriggers)
trigger();
}
}
}
public void OnActionStarted()
{
lock (_lockObj) //fix the error #EricLippert talked about in comments
IsInAction = true;
}
private ISet<Action> _triggers = new HashSet<Action>();
public void ExecuteAfterAction(Action action)
{
lock (_lockObj)
{
if (IsInAction)
_triggers.Add(action);
else
action();
}
}
public bool IsInAction
{
get;private set;
}
}
This guarantees that one cannot iterate over the collection and modifying it at the same time.
No. You have a reentrancy problem.
Consider what happens if inside the call to trigger (same thread, so lock is already held), you modify the collection:
csharp
foreach (var trigger in _triggers)
trigger(); // _triggers modified in here
In fact if you look at your full callstack, you will be able to find the frame that is enumerating the collection. (by the time the exception happens, the code that modified the collection has been popped off the stack)
I have a web service that has a default ErrorLog method for adding Logs to a Db Table. If there's an exception is caught on the ErrorLog Add or the Stored Procedure returns that it failed to add. I'd like to write the error to a textfile on the server, (in theory this should never happen).
Now before actually implementing this, I realize there's a good chance that multiple people could get an error, all of them fail, and all of them try to write to the same text file.
How can I implement a queue on the service, so that the messages get added to the queue and another service / job loops through this queue and adds the errors to the file?
I have tried looking for examples, most of them are very basic. The only thing I really want to know is how I should keep track of the queue? Do I simply create a static class?
Would the below work?
public class ErrorLogging
{
public ErrorLogging(Error error)
{
if (ErrorLoggingQueue._GlobalQueue == null)
{
ErrorLoggingQueue._GlobalQueue = new Queue<Error>();
}
ErrorLoggingQueue._GlobalQueue.Enqueue(error);
}
}
public static class ErrorLoggingQueue
{
public static Queue<Error> _GlobalQueue;
}
// Assume that this class/method gets called every x minutes or seconds from a job or something.
public class JobClass
{
public void WriteErrors()
{
if (ErrorLoggingQueue._GlobalQueue != null)
{
while (ErrorLoggingQueue._GlobalQueue.Count != 0)
{
Error error = (Error)ErrorLoggingQueue._GlobalQueue.Dequeue();
// Do stuff here
}
}
}
}
Yes, static variable with a Queue will work and would be shared between requests. Just add locking for enqueue and dequeue to make those operation atomic. Something along these lines:
class YourWebservice
{
static Queue<Error> _GlobalQueue = new Queue<Error>();
static readonly object queueLock = new object();
static Thread errorLogger;
public void SomeWebserviceMethod()
{
//Some code...
//.
//.
//Here we want to log an error
EnqueueError(new Error());
}
private void EnqueueError(Error err )
{
lock(queueLock)
{
_GlobalQueue?.Enqueue(err);
if ( errorLogger==null || !(errorLogger?.IsAlive ?? false) )
{
errorLogger = new Thread(new ThreadStart(WriteErrors));
errorLogger?.Start();
}
}
}
private static Error DequeueError()
{
try
{
lock (queueLock)
{
return _GlobalQueue?.Dequeue();
}
}
catch(Exception)
{
//if we got here it means queue is empty.
}
return null;
}
private static void WriteErrors()
{
Error error = DequeueError();
while (error!=null)
{
//Log error here
//...
//..
error = DequeueError();
}
}
}
I am writing extension methods for a class, and would like to access an IDisposable object defined in a using block which will often contain calls to the extension methods.
I do not want to simply pass the IDisposable to the method calls, which would detract from the simplicity of my API's programming model. Accomplishing what I'm after would also make the code work much more like the third-party API with which I'm integrating.
I can imagine one way to go about this: register the IDisposable in some global location, perhaps tied to the current thread ID so it can be looked up in the extension methods via a factory method call or some such thing. The object could unregister itself when the using block is exited and its Dispose() method is eventually called (to make this work I imagine I might need to use a weak reference, though).
That doesn't seem very unclean, but it is a little too much roundabout for my taste. Is there some more direct way of doing this?
Here's what I'd like to do:
public static class ExtensionMethods {
public static void Foo(this Bar b) {
// Access t to enable this extension method to do its work, whatever that may be
}
}
public class Bar {
}
public class Schlemazel {
public void DoSomething() {
using (Thingamabob t = new Thingamabob()) {
Bar b = new Bar();
b.Foo();
}
}
}
EDIT:
Following is a solution implemented using weak references and a simple thread-based registration system. It seems to work and to be stable even under a fair load, but of course on a really overloaded system it could theoretically start throwing errors due to lock contention.
I thought it might be interesting for someone to see this solution, but again, it introduces needless complexity and I am only willing to do this if necessary. Again, the goal is a clean extension of a third-party API, where I can call extension methods on objects created by the third-party API, where the extension methods depend on some context that is messy to create or get for each little extension method call.
I've left in some console output statements so that if you're curious, you can actually plop these classes into a command-line project and see it all in action.
public class Context : IDisposable
{
private const int MAX_LOCK_TRIES = 3;
private static TimeSpan MAX_WRITE_LOCK_TIMEOUT = TimeSpan.FromTicks(500);
private static System.Threading.ReaderWriterLockSlim readerWriterLock = new System.Threading.ReaderWriterLockSlim();
static IDictionary<string, WeakReference<Context>> threadContexts = new Dictionary<string, WeakReference<Context>>();
private bool registered;
private string threadID;
private string ThreadID
{
get { return threadID; }
set
{
if (threadID != null)
throw new InvalidOperationException("Cannot associate this context with more than one thread");
threadID = value;
}
}
/// <summary>
/// Constructs a Context suitable for use in a using() statement
/// </summary>
/// <returns>A Context which will automatically deregister itself when it goes out of scope, i.e. at the end of a using block</returns>
public static Context CreateContext()
{
Console.WriteLine("CreateContext()");
return new Context(true);
}
private Context(bool register)
{
if (register)
{
registered = true;
try
{
RegisterContext(this);
}
catch
{
registered = false;
}
}
else
registered = false;
}
public Context()
{
registered = false;
}
public void Process(ThirdPartyObject o, params string[] arguments)
{
Console.WriteLine("Context.Process(o)");
// Process o, sometimes using the third-party API which this object has access to
// This hides away the complexity of accessing that API, including obviating the need
// to reconstruct and configure heavyweight objects to access it; calling code can
// blithely call useful methods on individual objects without knowing the messy details
}
public void Dispose()
{
if (registered)
DeregisterContext(this);
}
private static void RegisterContext(Context c)
{
if (c == null)
throw new ArgumentNullException();
c.ThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
Console.WriteLine("RegisterContext() " + c.ThreadID);
bool lockEntered = false;
int tryCount = 0;
try
{
while (!readerWriterLock.TryEnterWriteLock(TimeSpan.FromTicks(5000)))
if (++tryCount > MAX_LOCK_TRIES)
throw new OperationCanceledException("Cannot register context (timeout)");
lockEntered = true;
threadContexts[c.ThreadID] = new WeakReference<Context>(c);
}
finally
{
if (lockEntered)
readerWriterLock.ExitWriteLock();
}
}
private static void DeregisterContext(Context c)
{
if (c == null)
throw new ArgumentNullException();
else if (!c.registered)
return;
Console.WriteLine("DeregisterContext() " + c.ThreadID);
bool lockEntered = false;
int tryCount = 0;
try
{
while (!readerWriterLock.TryEnterWriteLock(TimeSpan.FromTicks(5000)))
if (++tryCount > MAX_LOCK_TRIES)
throw new OperationCanceledException("Cannot deregister context (timeout)");
lockEntered = true;
if (threadContexts.ContainsKey(c.ThreadID))
{
Context registeredContext = null;
if (threadContexts[c.ThreadID].TryGetTarget(out registeredContext))
{
if (registeredContext == c)
{
threadContexts.Remove(c.ThreadID);
}
}
else
threadContexts.Remove(c.ThreadID);
}
}
finally
{
if (lockEntered)
readerWriterLock.ExitWriteLock();
}
}
/// <summary>
/// Gets the Context for this thread, if one has been registered
/// </summary>
/// <returns>The Context for this thread, which would generally be defined in a using block using Context.CreateContext()</returns>
internal static Context GetThreadContext()
{
string threadID = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
Console.WriteLine("GetThreadContext() " + threadID);
bool lockEntered = false;
int tryCount = 0;
try
{
while (!readerWriterLock.TryEnterReadLock(TimeSpan.FromTicks(5000)))
if (++tryCount > MAX_LOCK_TRIES)
throw new OperationCanceledException("Cannot get context (timeout)");
lockEntered = true;
Context registeredContext = null;
if (threadContexts.ContainsKey(threadID))
threadContexts[threadID].TryGetTarget(out registeredContext);
return registeredContext;
}
finally
{
if (lockEntered)
readerWriterLock.ExitReadLock();
}
}
}
// Imagine this is some third-party API
public static class ThirdPartyApi
{
// Imagine this is any call to the third-party API that returns an object from that API which we'd like to decorate with an extension method
public static ThirdPartyObject GetThirdPartyObject()
{
return new ThirdPartyObject();
}
}
// Imagine this is some class from a third-party API, to which we would like to add extension methods
public class ThirdPartyObject
{
internal ThirdPartyObject() { }
}
public static class ExtensionMethods
{
public static void DoSomething(this ThirdPartyObject o) {
// get the object I need to access resources to do my work
Console.WriteLine("o.DoSomething()");
Context c = Context.GetThreadContext();
c.Process(o);
}
}
You could test it pretty simply, with some code like this:
ThirdPartyObject o;
using (Context.CreateContext())
{
o = ThirdPartyApi.GetThirdPartyObject(); // or a call to my own code to get it, encapsulating calls to the third-party API
// Call the method we've tacked on to the third party API item
o.DoSomething();
}
try
{
// If the registered context has been disposed/deregistered, this will throw an error;
// there is of course no way of knowing when it will happen, but in my simple testing
// even this first attempt always throws an error, on my relatively unburdened system.
// This means that with this model, one should not access the using-block Context
// outside of the using block, but that's of course true in general of using statements
o.DoSomething();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
System.Threading.Thread.Sleep(1000);
try
{
// Should almost certainly see an error now
o.DoSomething();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Pass the t variable to the extension method.
public static class ExtensionMethods {
public static void Foo(this Bar b, Thingamabob t) {
// Access t to enable this extension method to do its work, whatever that may be
}
}
public class Bar { }
public class Schlemazel {
public void DoSomething() {
using (Thingamabob t = new Thingamabob()) {
Bar b = new Bar();
b.Foo(t);
}
}
}
I need to try to lock on an object, and if its already locked just continue (after time out, or without it).
The C# lock statement is blocking.
Ed's got the right function for you. Just don't forget to call Monitor.Exit(). You should use a try-finally block to guarantee proper cleanup.
if (Monitor.TryEnter(someObject))
{
try
{
// use object
}
finally
{
Monitor.Exit(someObject);
}
}
I believe that you can use Monitor.TryEnter().
The lock statement just translates to a Monitor.Enter() call and a try catch block.
I had the same problem, I ended up creating a class TryLock that implements IDisposable and then uses the using statement to control the scope of the lock:
public class TryLock : IDisposable
{
private object locked;
public bool HasLock { get; private set; }
public TryLock(object obj)
{
if (Monitor.TryEnter(obj))
{
HasLock = true;
locked = obj;
}
}
public void Dispose()
{
if (HasLock)
{
Monitor.Exit(locked);
locked = null;
HasLock = false;
}
}
}
And then use the following syntax to lock:
var obj = new object();
using (var tryLock = new TryLock(obj))
{
if (tryLock.HasLock)
{
Console.WriteLine("Lock acquired..");
}
}
Consider using AutoResetEvent and its method WaitOne with a timeout input.
static AutoResetEvent autoEvent = new AutoResetEvent(true);
if(autoEvent.WaitOne(0))
{
//start critical section
Console.WriteLine("no other thread here, do your job");
Thread.Sleep(5000);
//end critical section
autoEvent.Set();
}
else
{
Console.WriteLine("A thread working already at this time.");
}
See https://msdn.microsoft.com/en-us/library/cc189907(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.threading.autoresetevent(v=vs.110).aspx and https://msdn.microsoft.com/en-us/library/cc190477(v=vs.110).aspx
You'll probably find this out for yourself now that the others have pointed you in the right direction, but TryEnter can also take a timeout parameter.
Jeff Richter's "CLR Via C#" is an excellent book on details of CLR innards if you're getting into more complicated stuff.
Based on Dereks answer a little helper method:
private bool TryExecuteLocked(object lockObject, Action action)
{
if (!Monitor.TryEnter(lockObject))
return false;
try
{
action();
}
finally
{
Monitor.Exit(lockObject);
}
return true;
}
Usage:
private object _myLockObject;
private void Usage()
{
if (TryExecuteLocked(_myLockObject, ()=> DoCoolStuff()))
{
Console.WriteLine("Hurray!");
}
}