Sto scrivendo una classe che contiene dati. Espone metodi che consentono di interrogare i dati, mentre i dati vengono anche aggiornati da una fonte esterna (servizio web, ad esempio).
Tutti i metodi espongono le attività avviate su un thread di lavoro utilizzando l'utilità di pianificazione predefinita. Quindi la struttura della classe è la seguente:
public class A
{
private object _myLock;
public Task<int> GetSomeNumber(int aParameter)
{
return Task.Run(() =>
{
lock (_myLock)
{
int result = 0;
// calculate the result...
// ...
return result;
}
});
}
public Task<string> GetSomeText(int aParameter)
{
return Task.Run(() =>
{
lock (_myLock)
{
string result = "";
// calculate the result...
// ...
return result;
}
});
}
}
I metodi possono essere chiamati più volte, mentre i dati stessi vengono aggiornati, quindi i calcoli che richiedono i dati condivisi sono circondati da un'istruzione di blocco. Il problema è che questo codice blocca il thread in cui viene eseguita l'attività. Naturalmente, questi non sono thread dell'interfaccia utente, quindi l'interfaccia utente rimane reattiva, ma consuma thread e li mantiene bloccati. Preferirei che i thread di lavoro nel pool di thread restassero il più possibile disponibili.
Esiste un modo, una best practice di qualche tipo, che permetta di scrivere questo codice in modo che i dati condivisi siano thread-safe e allo stesso tempo le attività non siano bloccate? Se invece di aspettare un lock, le attività dovrebbero aspettare che qualcun altro finisca (un'attività), vorrei usare ContinueWith
per creare un'attività di continuazione e restituirla, in modo che fosse programmata per essere eseguita quando il primo compito è completato. C'è un modo per fare lo stesso con il blocco, in modo che l'attività sia pianificata solo quando il blocco è disponibile?
Aggiorna
Ho fatto alcune letture e ho scoperto diverse possibili opzioni che consentono la sincronizzazione di dati condivisi. Questi includono: SemaphoreSlim
, AsyncLock
e ConcurrentExclusiveSchedulerPair
.
Mi piacerebbe vedere una raccomandazione per una procedura ottimale, di scrivere una classe di servizio che fornisca metodi di attività "sola lettura" che possano essere eseguiti simultaneamente con un blocco di lettura e metodi di scrittura "write" che richiedono il blocco della scrittura.