Implementé la sincronización de tareas usando Monitor en C#. Sin embargo, he leído que Monitor no debe usarse en operación asincrónica.
En el siguiente código, ¿cómo implemento los métodos Monitor Wait y PulseAll con una construcción que funciona con Task (operaciones asíncronas)?
He leído que los métodos SemaphoreSlim.WaitAsync y Release pueden ayudar. Pero, ¿cómo encajan en el ejemplo a continuación, donde varias tareas deben esperar en un objeto de bloqueo, y al liberar el bloqueo se activan todas las tareas en espera?
private bool m_condition = false; private readonly Object m_lock = new Object(); private async Task<bool> SyncInteralWithPoolingAsync( SyncDatabase db, List<EntryUpdateInfo> updateList) { List<Task> activeTasks = new List<Task>(); int addedTasks = 0; int removedTasks = 0; foreach (EntryUpdateInfo entryUpdateInfo in updateList) { Monitor.Enter(m_lock); //If 5 tasks are waiting in ProcessEntryAsync method if(m_count >= 5) { //Do some batch processing to obtian values to set for adapterEntry.AdapterEntryId in ProcessEntryAsync //....... //....... m_condition = true; Monitor.PulseAll(m_lock); // Wakes all waiters AFTER lock is released } Monitor.Exit(m_lock); removedTasks += activeTasks.RemoveAll(t => t.IsCompleted); Task processingTask = Task.Run( async () => { await this.ProcessEntryAsync( entryUpdateInfo, db) .ContinueWith(this.ProcessEntryCompleteAsync) .ConfigureAwait(false); }); activeTasks.Add(processingTask); addedTasks++; } } private async Task<bool> ProcessEntryAsync(SyncDatabase db, EntryUpdateInfo entryUpdateInfo) { SyncEntryAdapterData adapterEntry = updateInfo.Entry.AdapterEntries.FirstOrDefault(e => e.AdapterId == this.Config.Id); if (adapterEntry == null) { adapterEntry = new SyncEntryAdapterData() { SyncEntry = updateInfo.Entry, AdapterId = this.Config.Id }; updateInfo.Entry.AdapterEntries.Add(adapterEntry); } m_condition = false; Monitor.Enter(m_lock); while (!m_condition) { m_count++; Monitor.Wait(m_lock); } m_count--; adapterEntry.AdapterEntryId = .... //Set Value obtained form batch processing Monitor.Exit(m_lock); } private void ProcessEntryCompleteAsync(Task<bool> task, object context) { EntryProcessingContext ctx = (EntryProcessingContext)context; try { string message; if (task.IsCanceled) { Logger.Warning("Processing was cancelled"); message = "The change was cancelled during processing"; } else if (task.Exception != null) { Exception ex = task.Exception; Logger.Warning("Processing failed with {0}: {1}", ex.GetType().FullName, ex.Message); message = "An error occurred while synchronzing the changed."; } else { message = "The change was successfully synchronized"; if (task.Result) { //Processing //... //... } } } catch (Exception e) { Logger.Info( "Caught an exception while completing entry processing. " + e); } finally { } }Gracias