Requires improved thread lock recommendation

I have the following script:

I am trying to block a thread in place if this "user" identifier of these threads matches the one that has already entered the lock code, but does not differ from the identifier.

I created some code examples to explain the behavior I want

class A { private static Dictionary<int, object> _idLocks = new Dictionary<int, object>(); private static readonly object _DictionaryLock = new object(); private int _id; private void A (int id) { _id = id; } private object getObject() { lock (_DictionaryLock) { if (!_idLocks.ContainsKey(_id)) _idLocks.Add(_id, new object()); } lock (_idLocks[_id]) { if (TestObject.Exists(_id)) return TestObject(_id); else return CreateTestObject(_id); } } } 

Now it works 100% for what I expanded where the id of example 1 does not check if its object was created and another thread with id 1 is already busy creating this object.

But having two locks and a static dictionary does not seem to be the right way to do this at all, so I hope someone can show me an improved method to stop the stream from accessing the code only if this stream was created with the same id, since it is already taken code execution in the blocked section.

I was looking at the ReaderWriterLockSlim class, but that didnโ€™t make sense to me because I donโ€™t want the TestObject (id) object to be read at all while it is still being created.

I do not need to block the stream from accessing the dictionary. What I'm trying to avoid at all costs is the _id that runs this thread, should not be used inside CreateTestObject(_id) while it is already busy, because files are created and deleted with this identifier, which throws an exception if two threads try access the same files

This fix is โ€‹โ€‹with a normal lock, but in this case I still need a thread where _id does not currently work inside the CreateTestObject(_id) method to be able to enter code inside the lock.

This is all because what happens inside CreateTestObject takes time and performance if the thread expects access to it.

+5
source share
2 answers

It sounds like you are using this code to populate a dictionary in a thread-safe way - could you please use ConcurrentDictionary instead?

 class A { private static ConcurrentDictionary<int, object> _dictionary = new ConcurrentDictionary<int, object>(); private int _id; private object GetObject() { object output = null; if(_dictionary.TryGetValue(_id, output)) { return output; } else { return _dictionary.GetOrAdd(_id, CreateTestObject(_id)); } } } 

Edit: if you want to completely eliminate the possibility of calling repeated CreateTestObject methods, you can save the wrapper in _dictionary , which lazily sets object

 class Wrapper { private volatile object _obj = null; public object GetObj() { while(_obj == null) { // spin, or sleep, or whatever } return _obj; } public void SetObj(object obj) { _obj = obj; } } class A { private static ConcurrentDictionary<int, Wrapper> _dictionary = new ConcurrentDictionary<int, Wrapper>(); private int _id; private object GetObject() { Wrapper wrapper = null; if(_dictionary.TryGetValue(_id, wrapper)) { return wrapper.GetObj(); } else { Wrapper newWrapper = new Wrapper(); wrapper = _dictionary.GetOrAdd(_id, newWrapper); if(wrapper == newWrapper) { wrapper.SetObj(CreateTestObject(_id)); } return wrapper.GetObj(); } } } 

Only one thread can put a new Wrapper in _dictionary in the specified _id - this thread initializes the object inside the wrapper == newWrapper . Wrapper#GetObj rotates until the object is installed, this can be rewritten instead.

+3
source

This may not work, because Monitor (which is used inside the lock statement) is repetitive. This means that the thread can enter any lock that it already owns as many times as necessary.

You could solve this problem using Semaphore instead of Monitor , but stop for a while and listen to what you ask for - you want the thread to lock on lock to belong to the same topic, How will this thread ever wake up? It will be locked forever - waiting for the lock released, as well as for those who have a lock .

Or are you just trying to handle the lazy initialization of an object without blocking all other threads? This is actually quite simple:

 ConcurrentDictionary<int, YourObject> dictionary; return dictionary.GetOrAdd(id, i => CreateTestObject(i)); 

Please note that CreateTextObject is called only if the key does not already exist in the dictionary.

0
source

All Articles