У меня есть хранилище элементов, которое используется как для view-модели (основной поток), так и для фонового сервиса (фоновый поток).
Оба могут запрашивать хранилище элементов и обновлять элементы.
class ItemRepository
{
Item GetItem(int id);
void UpdateItem(Item item);
}
public class Item
{
ItemState State { get; set; }
}
// Component A (view-model)
// Runs on main thread
void ExecuteUpdateItemCommand()
{
var item = _itemRepo.GetItem(1);
if(item.State == ItemState.First)
{
itemState.State = ItemState.Second;
_itemRepo.UpdateItem(item); // Ideally this should be on a separate thread but for now lets' assume it's on main thread
}
}
// Component B (background service - receives notifications from backedn)
// Runs on a background thread
void OnNotificationReceived()
{
var item = _itemRepo.GetItem(1);
if(item.State == ItemState.First)
{
item.State = GetNextState(); // some busines logic specific to Component B
_itemRepo.UpdateItem(item);
}
}
Проблема, с которой я столкнулся, заключается в реализации синхронизации запроса элемента и обновлении в двух потоках.
Без синхронизации состояние элемента может стать поврежденным, поскольку после возврата оператора if в одном потоке другой поток может обновлять состояние элемента на другое значение, что может нарушить бизнес-логику состояния элемента.
Простым решением является блокировка компонента A и компонента B на одном и том же общем объекте. С точки зрения дизайна, как разделить этот объект между компонентами (каждый со своей целью)?
Другое решение, которое я вижу, состоит в том, чтобы иметь службу, которая выполняет и бизнес-логику компонента A и компонента B только для синхронизации вызовов, но, на мой взгляд, это не очень хорошее решение.
Я ищу лучшие реализации, чем эти.
Мне кажется, хорошее решение может быть таким, которое позволяет мне управлять вещами в контексте. Что-то вроде
ItemSyncContext.Run(ExecuteUpdateItemCommand);
и
ItemSyncContext.Run(OnNotificationReceived);