Reputation:
I have a bunch of DB entities that are loaded into DB objects. The same DB entity may be loaded into more than DB object. Periodically a DB entity will require special processing. This processing must be performed by one thread at a time. Locking is in order here.
EDIT: Important note: the process calls a slow web service. This is what I'm trying to prevent concurrency. I don't see how this can be done safely w/o locks.
So I create an “padlock” object that will be referenced by the DB objects for locking. The padlock object is entity based so that two or more DB objects for the same entity will use the same padlock object. I’m storing these padlocks in a dictionary object using the DB entity’s ID as the key. The padlock object is just a simple string object as well. Is this the right approach? I'm thinking I'm either over engineering or simplifying this. If the approach is correct, how does this code look? It works, but I've yet to test it under load.
Thanks :)
public static func(CustomObject o)
{
if (ReadyForUpdate(o))
{
lock (LookupPadLockByID(object.ID)
{
if (ReadyForUpdate(o))
{
PerformUpdate(object);
}
}
}
}
private static readonly object padlockLock = new object();
private static readonly Dictionary<int, string> padLocks = new Dictionary<int,string>();
private static object LookupPadLockByID(int uniqueID)
{
lock (padlockLock)
{
if (!padLocks.ContainsKey(uniqueID))
{
padLocks.Add(uniqueID, uniqueID + " is locked");
}
}
return padLocks[uniqueID];
}
Upvotes: 0
Views: 6354
Reputation: 41690
Locking on a string is not a good idea. I suggest two alternatives:
Dictionary<int,object>
as padLocks' type, and put a new object();
as the value.LockPad class:
class LockPad {
public int Id { get; private set; }
public LockPad(int id) {
this.Id = id;
}
public override string ToString() {
return "lock of " + id.ToString();
}
}
Then, lock on that class.
Upvotes: 1
Reputation: 4426
If you're using a standard Database of any type, I would suggest dumping these client-side locks entirely in favor of transactions and table/row locks.
Upvotes: 0
Reputation: 295
I think you are over engineering. If you only need to protect your DB entities (which I assume is represented by "object" in your code, which I will change to "entity"), you can just use it as your lock. Any reference object can be used as a lock:
public static func(CustomObject o)
{
if (ReadyForUpdate(o))
{
lock (entity)
{
if (ReadyForUpdate(o))
{
PerformUpdate(entity);
}
}
}
}
Upvotes: 0
Reputation: 1064204
Well, you end up locking on a string, which isn't a good idea (although the concatenation means that interning shouldn't be a huge issue). What is a bigger issue is that:
padLocks
- is that an issue?padlockLock
; the return
should be inside the lock
For this second, this would be simpler:
object itemLock;
if (!padLocks.TryGetValue(uniqueID, out itemLock)) {
itemLock = new object();
padLocks.Add(uniqueID, itemLock);
}
return itemLock;
If this code is fairly local (i.e. your objects haven't escaped yet), you might simply lock
the record itself? A lot simpler...
Upvotes: 1