Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collection Contracts and Threading

Suppose I have a custom collection class that provides some internal thread synchronization. For instance, a simplified Add method might look like this:

    public void Add(T item)
    {
        _lock.EnterWriteLock();
        try
        {
            _items.Add(item);
        }
        finally
        {
            _lock.ExitWriteLock();
        }
    }

The latest Code Contracts complains that CodeContracts: ensures unproven: this.Count >= Contract.OldValue(this.Count). The problem is that this really can't be proven. I can ensure that, internally, within the lock, Count will be greater than its previous value. I cannot ensure this, however, at the exit of the method. After the lock is exited and before the method completes, another thread could issue two Removes (likely of different elements), invalidating the contract.

The fundamental issue here is that the collection contracts can only be considered valid from within a particular locking context and only if the locking is used consistently throughout the application for all access to the collection. My collection must be used from multiple threads (with non-conflicting Add and Remove being a valid use case), but I would still like to implement ICollection<T>. Should I simply pretend that I can meet this ensures requirement with an Assume, even though I know I can't? It strikes me that none of the BCL collections can actually ensure this either.


EDIT:

Based on some further investigation, it sounds like the biggest issue is that the contract rewriter can introduce incorrect assertions, leading to runtime failures. Based on this, I think my only option is to restrict my interface implementation to IEnumerable<T>, as the contract on ICollection<T> implies that the implementing class cannot provide internal thread synchronization (access must always be synchronized externally.) This is acceptable for my particular case (all clients that wish to mutate the collection know about the class type directly), but I'm definitely interested to hear if there are other solutions to this.

like image 716
Dan Bryant Avatar asked Oct 06 '10 16:10

Dan Bryant


1 Answers

As you imply, no implementer can meet this contract. Indeed generally in the face of multi-threading unless the contract can be applied like:

 Take Lock
 gather Old Stuff

 work

 check Contract, which may compare Old Stuff
 Release Lock

I don't see how any contract could be honoured. From what I can see here this is an area that's not fully baked yet.

I think that using an Assume is the best you can do, in effect you are saying "by calling Add I am doing what the contract expects".

like image 151
djna Avatar answered Oct 12 '22 16:10

djna