Sto cercando di capire un'implementazione per una soluzione a un problema che ho delineato in un'altra domanda Programmers.SE . Ho bisogno di trovare una soluzione per questo problema in C # molto probabilmente usando la collezione nello spazio dei nomi System.Collections.Concurrent
.
Il mio problema è un classico problema relativo al Problema dei filosofi in sala . Ho un insieme finito di risorse che devono essere utilizzate da più thread. La mia attuale implementazione di una soluzione implica una sorta di sistema di segnalazione per far sapere agli altri thread quando possono iniziare a usare una risorsa. In realtà ho creato una bella analogia.
Le risorse sono viste come giostre dei parchi di divertimento che possono essere adattate a un solo pilota alla volta. Thread / compiti / unità di lavoro sono visti come gruppi di persone che desiderano guidare più corse diverse allo stesso tempo.
Quando un gruppo di persone entra nel parco si fermano allo stand di biglietteria, ognuno acquista un biglietto per il rispettivo giro e si mette in fila per le rispettive linee, tutte simultaneamente . Ognuno di questi gruppi di persone comincerà a cavalcare solo una volta che saranno tutti in prima linea, altrimenti attenderanno i primi in fila alle rispettive corse fino a quando tutti saranno in prima fila.
Questa soluzione funzionerebbe ma la raccolta simultanea in C # rende difficile l'implementazione corretta. (Andando avanti con l'analogia) Come risultato di ogni persona del gruppo che deve acquistare i biglietti e mettersi in fila tutti contemporaneamente, a un certo punto devo fare atomicamente più modifiche ad alcune raccolte simultanee. In C # non esiste un meccanismo per farlo in System.Collections.Concurrent
.
In C # ho le seguenti strutture dati per rappresentare l'analogia sopra
ConcurrentDictionary<IResource, ConcurrentQueue<Guid>> ResourceWaitQueues { get; set; }
ConcurrentDictionary<ITask, ConcurrentDictionary<IResource, Guid>> TasksToDo { get; set; }
[Passaggio 1.a] quando viene generata una nuova ITask
, viene interrogata per IResource
s che deve essere eseguita. Per ogni IResource
è necessario un nuovo Guid
generato. A KeyValuePair
viene creato per questo ITask
e inserito in TasksToDo
.
[Passaggio 1.b] Il Guid
creato per ogni IResource
il ITask
necessario viene quindi inserito nel corrispondente ConcurrentQueue<Guid>
nell'oggetto ResourcesWaitQueues
.
[DispatchThread] Il thread di dispatch (TPL Task
) viene avviato. Questo thread scorre continuamente sulla struttura TasksToDo
e controlla se il ITask
corrente di List<Guid>
necessario per l'esecuzione si trova nella parte anteriore di ConcurrentQueue
s in ResourceWaitQueues
. Se è così, viene avviato, altrimenti viene saltato.
[TaskRunningThread] quando viene trovato un ITask
pronto per essere eseguito, viene eseguito. Una volta completato, il List<Guid>
in attesa viene rimosso dalla rispettiva percentuale% di% in ConcurrentQueue
.
Come dovresti notare, il problema con questa soluzione è che devo aggiungere più o rimuovere ResourceWaitQueues
e ConcurrentQueue
quando viene generato un nuovo ConcurrentDictionary
o quando è stato completato un ITask
. Se DispatchThread o TaskRunningThread riesce a intercalarsi tra loro, è possibile che ITask
non venga mai aggiunto o rimosso dalle rispettive raccolte.
Mi piacerebbe pensare di essere abbastanza esperto da scrivere la mia collezione simultanea per consentire più modifiche atomiche, anche se preferirei usare le classi ben sviluppate.
Quindi la mia domanda è, c'è un modo per risolvere questo problema con le collezioni Guid
fuori dalla lista?