I have an dynamic list of objects I am tracking, and may in the future use many threads. Can someone look at this implementation for errors?
In other words I want to track a many instances of this object:
object AzureBatchTrackerLock = new object();
Dictionary<string, List<TableServiceEntity>> AzureBatchTracker = new Dictionary<string, List<TableServiceEntity>>();
My current approach is to use lock with dedicated objects, and List and Dictionry to handle the dynamic arrays…
BatchThread.cs
/// This object itself contains a dictionary AND a lock.
/// This object will ALSO be contained in a second dictionary that also has its own lock
public class BatchThread
{
// When I perform updates to AzureBatchTracker dictionary, lock the following
internal readonly object AzureBatchTrackerLock = new object();
internal Dictionary<string, List<TableServiceEntity>> AzureBatchTracker = new Dictionary<string, List<TableServiceEntity>>();
}
BatchProcessor.cs
public class BatchProcessor
{
// Class-wide scope
readonly object _BatchEntriesLock = new object();
Dictionary<string, BatchThread> _BatchEntries = new Dictionary<string, BatchThread>();
// The "outer loop"
public BatchThread GetAnEntry(string ThingToProcess)
{
// Prepare return variable
BatchThread foundBatchThread = null;
// And then I would select an object like this:
// Notice that I'm performing what may be a concurrent entry here
// on a non-locked object ............................
// Is this a bad idea? Should I lock? Does it matter?
// If I must lock, want to exit as quickly as possible. Must not be later than the next lock() command
var activeRow = _BatchEntries[ThingToProcess];
// Since I have the object I care about, I'll work with the "secondary" lock object
// It works in practice, but I don't know what kind concurrency issues I'll run into.
lock (activeRow.Value.AzureBatchTrackerLock)
{
// Add and remove from the collection
ActiveRow.Value.AzureBatchTracker.Add(new exampleEntry);
// Do Stuff
ActiveRow.Value.AzureBatchTracker.Remove(something);
foundBatchThread = activeRow.Value.AzureBatchTracker[ThingToProcess];
}
return foundBatchThread;
}
// The inner loop
// Called whenever the "Outer" array needs to be expanded
public void AddNewBatchEntry(string newEntryName)
{
lock (_BatchEntriesLock)
{
// Add placeholder to the collection
_BatchEntries.Add( newEntryName, new BatchThread() );
// Do Stuff
}
}
}
Do you see any flaws in this implementation? Is there a better way?
Yes, you’ll need to lock on
var ActiveRow = BatchEntries[ThingToProcess];, because you’re also adding to the dictionary (unless you’re sure they happen at seperate times). If you can gaurantee you won’t be adding while the ‘outer loop’ is executing, then no, you don’t need to lock – you can have concurrent reads.If the add method happens rarely, with lots of reads, you should look into ReaderWriterLock