Question

I am creating a class, say LockHolder, to simplify the lock requiring logic. It implements the IDisposable interface, thus I can use it like this:

using(LockHolderCreater.Create(lockObject, waittime))
{
    //do something
}

The Dispose method of LockHolder releases lockObject (through Monitor.Exit) if it has been gained (through Monitor.TryEnter). That works fine if I create a new LockHolder object everytime LockHolderCreater.Create is called, but that would create too many instances of LockHolder. So I Write LockHolderCreater to maintain a list of LockHolder objects in order to reuse them. Now I am facing too problems:

First, when debugging, I found there are many such message as "A first chance exception of type 'System.ObjectDisposedException' occurred in System.dll" in the output window. If what the "using" statement do is just to call the Dispose method, can I prevent this kind of exception?

Second, and more importantly, if I reuse the LockerHolder instances, at some early time after my application starts, a SynchronizationLockException exception would be thrown when I try to release a lock in the Dispose method, saying that "Object synchronization method was called from an unsynchronized block of code.". I checked my logic, but I don't think it is possible that one LockHolder instance would be used by two threads at the same time. Can this be related with the ObjectDisposedException noted above?

ABOUT the answer

I don't get a direct answer of my question, but Marc Gravell's answer has made it less neccessary.

Était-ce utile?

La solution

Should you do it: probably not, except for very exceptional scenarios where you are in complete control of the types.

Can you do it: this depends entirely on the implementation - and you certainly wouldn't want to apply that at random to arbitrary types. If, however, the type is (as part of cleanup) returned to some pool and re-initialized and re-used, then yes it will work. But: you risk problems if the // do something code leaked the reference somewhere.

can I prevent this kind of exception?

yes: don't access an object after you've disposed it

saying that "Object synchronization method was called from an unsynchronized block of code."

I wonder - are you perhaps using await here? or an iterator block? or something like that? If the enter and exit code runs on different threads, it will fail.

If your intent here is to minimize allocations of LockerHolder, there is a better approach: use a struct:

using System;

struct Foo : IDisposable
{
    public Foo(string msg)
    {
        Console.WriteLine("Init: " + msg);
    }
    public void Dispose()
    {
        Console.WriteLine("Disposed");
    }

}

static class Program
{
    static void Main()
    {
        Console.WriteLine("Before");
        using (new Foo("Hi"))
        {
            Console.WriteLine("Do stuff");
        }
        Console.WriteLine("After");
    }
}

The Main method here compiles the Dispose using constrained-call, which means it doesn't box.

Note that for this to work, the LockHolderCreater.Create method must return the struct itself - it cannot return just IDisposable.

Autres conseils

Declaring the variable inside the using statement's control expression limits the scope of the variable to inside the using statement.

Check this answer

It is a bad idea to abuse the using statement. It is not intended as a general-purpose "automatic undo". It is only intended as a means to ensure the disposal of unmanaged resources like database connections.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top