Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does locking with many different objects has an impact performance wise comparing to only one?

I don't know if the question is stupid or not, locking and the Monitor is kind a black box to me.

But I'm dealing with a situation where I can either use the same lock object to lock everything all the time or use a indefinite number of object to lock at a more fine grain level.

I know that the second way will reduce the lock contention, but I may end up using 10K objects as locks and I don't know if it has an impact or not.

Bottom line: does too many locks hurt locking or it has no impact?

Edit

I wrote a lib that maintain a graph of objects, the number could be very high. For now it's not thread safe, mainly for the reason Eric stated in his comment.

I initially thought that if the user wanted to do some multi-threading then he/she would have to take care of the locking.

But now I'm wondering that if I would have to make it thread-safe, what would be the best way to do it (note that making it thread-safe wouldn't be a short and easy ride for me so testing both solutions is something I can't do easily)?

As the purpose is to make each object of the graph thread-safe, then I could use the instance of the object for the lock when I want to access/modify its properties. I know it's the best way to reduce contention, but I don't know if it would scale as much as having only one lock for the whole graph.

I know there's a lot to consider, how many threads and especially (I think) the chance of an object being accessed/changed by multiple threads at a time (which I estimate to be pretty low). But I can't find accurate information about locks and their overhead in such case.

like image 254
Nock Avatar asked Aug 21 '14 21:08

Nock


People also ask

Why are locks needed in a multi threaded program?

A lock may be a tool for controlling access to a shared resource by multiple threads. Commonly, a lock provides exclusive access to a shared resource: just one thread at a time can acquire the lock and everyone accesses to the shared resource requires that the lock be acquired first.

What does lock () return when a the lock is being held 1?

Returns 1 if the lock is free (no one is using the lock), 0 if the lock is in use, and NULL if an error occurs (such as an incorrect argument).

What is the correct order for using a lock object?

A lock request is first generated by the program. Then this request goes to the Enqueue server and the lock is created in the lock table. The Enqueue server sets the lock and the program is finally ready to access data.

Can a thread acquire multiple locks?

With locking, deadlock happens when threads acquire multiple locks at the same time, and two threads end up blocked while holding locks that they are each waiting for the other to release.


1 Answers

To get a more clearer view of what's going on I looked at the source code of the Monitor class and its C++ counterpart in clr/src/vm/syncblk.cpp in the Shared Source Common Language Infrastructure released by Microsoft.

To answer my own question: no, having a lot of locks doesn't hurt in any harmful way I could think of.

What I learned:

1) A lock that's is already taken by the same thread is processed "almost free".

2) A lock that's taken for the first time is basically the cost of an InterlockedCompareExchange.

3) Multiple threads waiting for a lock is fairly cheap to track (a link list is maintained, O(1) complexity).

4) A thread waiting for a lock to release is by far the most costly use case, the implem first spinwaits to try to get out, but if it's not enough a thread switch will occurs, putting the thread to sleep until a mutex signals it's time to wake up because of the lock release.

I got my answer by digging for the 2): if you're always locking with the same object or 10K different one, it's basically the same (extra initialization is performed the first time you lock a given object, but it's not too bad). The InterlockedCompareExchange doesn't care about being called on the same or different memory location (AFAIK).

Contention is by far the most critical concern. Having many locks would reduce (drastically in my case) the chance of contention, so it can only be a good thing.

1) is also an important learned lesson: if I lock/unlock for each property change/access I can improve performances by locking the object first, then changing many properties and release the lock. This way there will be only one InterlockedCompareExchange and the lock/unlock inside the implementation of the property change/access will only increment an internal counter.

To dig deeper I would have to find more information about the implementation of the InterlockedCompareExchange, I think it relies on the CPU specific assembly instruction...

like image 159
Nock Avatar answered Oct 12 '22 23:10

Nock