Parallel execution: concurrency problem.. and possible solution

Jul 27, 2011 at 1:28 PM

Hi to all,

I have a little problem to share with you.
I did a small program which is executed in parallel, and each instance starts a JintEngine. (i use jint 0.9.0)

Each script executed by jint contains a call to a CLR object of mine, inizialized in the same way, and each execution except the first throws out the same jint exception:

"An item with the same key has already been added"

After wondering around for a while, i finally found out the point where the execution fails: in class CachedTypeResolver.cs

this is the original code

 

        public Type ResolveType(string fullname)
        {
            rwl.AcquireReaderLock(Timeout.Infinite);

            try
            {
                if (_Cache.ContainsKey(fullname))
                {
                    return _Cache[fullname];
                }
            }
            finally
            {
                rwl.ReleaseReaderLock();
            }

            Type type = null;
            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = a.GetType(fullname, false, false);

                if (type != null)
                {
                    break;
                }
            }

            rwl.AcquireWriterLock(Timeout.Infinite);

            try
            {
                _Cache.Add(fullname, type);
                return type;
            }
            finally
            {
                rwl.ReleaseWriterLock();
            }
        }

 

and this is my modification to make it work:

        public Type ResolveType(string fullname)
        {
            rwl.AcquireReaderLock(Timeout.Infinite);

            try
            {
                if (_Cache.ContainsKey(fullname))
                {
                    return _Cache[fullname];
                }
            }
            finally
            {
                rwl.ReleaseReaderLock();
            }

            Type type = null;
            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())
            {
                type = a.GetType(fullname, false, false);

                if (type != null)
                {
                    break;
                }
            }

            rwl.AcquireWriterLock(Timeout.Infinite);

            try
            {
                // MY EDIT: check again in cache dictionary
                if (_Cache.ContainsKey(fullname))
                    return _Cache[fullname];
// STOP EDITING
                _Cache.Add(fullname, type);
                return type;
            }
            finally
            {
                rwl.ReleaseWriterLock();
            }
        }

as you can see, i've just added a second check for the element in the second try block.

The problem occurs when 2 (or more) scripts (executed in parallel) try do add the same element to the _Cache dictionary.
The AcquireReaderLock stops correctly the executions of other scripts but, if the element is not on dictionary, is released before adding the item to the dictionary.. letting all other parallel executions to do the same operation.

With a second check the problem fades out, but its just a workaround i know its not a good way to do the trick.

I'd like to know what do you think of it, and which solution could be best to solve the problem.

Thanks in advance (and thanks for jint^)

Coordinator
Jul 27, 2011 at 5:41 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.