Threading Model, datasets and features
This article provides more details about how an application synchronizes access to features in a MemoryDataSet. Information about custom datasets can be found in Threading model, custom objects.
The following text only mentions working with a MemoryDataSet and features but everything in it also holds for working with a GroupDataSet, which is a kind of MemoryDataSet, and groups that are feature like objects that can be inserted into a GroupDataSet.
Datasets and features
A MemoryDataSet is a dataset that an application can insert its own features into. Carmenta Engine will read features from a MemoryDataSet in the same way as from any other dataset, which includes accessing it from a background thread. This means that an application must synchronize access to the dataset and any features that have been inserted into the dataset correctly so that Carmenta Engine never reads from the dataset while it or any features it contains are being modified.
Each MemoryDataSet instance provides its own lock that must be acquired to synchronize access to that specific dataset instance and any features it contains. Acquiring this lock is very efficient and it will only affect a background thread that tries to access that specific dataset, all other background threads are unaffected and can keep on running.
![]() |
The dataset lock is acquired by instantiating the Guard class using the constructor that takes a MemoryDataSet reference. The lock is released when the Guard is destroyed (or disposed in one of the garbage collected APIs).
The MemoryDataSet lock can be acquired very quickly but if you insert, remove or modify more than one feature at a time you should, for best performance, structure your code so that you can acquire and release the lock once instead of once per feature.
The following code example shows how the MemoryDataSet lock can be used:
// Bulk insertion of features into a MemoryDataSet
void InsertFeatures(MemoryDataSet ds)
{
// Take the guard once (which will lock the dataset)
using (Guard g = new Guard(ds))
{
// Insert features at dummy position
for (int i = 0; i < 100; ++i)
{
ds.Insert(new Feature(new PointGeometry(0, i), ds.Crs));
}
} // The guard will be released here automatically
}
// Modify a feature that has been inserted into a MemoryDataSet. This method
// assumes that the dataset the feature has been inserted into is passed in
// the second argument. If the caller does not have a reference to the dataset
// when ModifyFeature() is called then it can find it like this:
//
// MemoryDataSet ds = DataSet.GetDataSetById(f.Id.DataSetId) as MemoryDataSet;
//
void ModifyFeature(Feature f, MemoryDataSet ds)
{
// Take the guard (which will lock the dataset)
using (Guard g = new Guard(ds))
{
// Modify the features attributes and/or geometry
f.Attributes["foo"] = "bar";
f.Geometry.Move(new Point(1, 1));
} // The guard will be released here automatically
}