private void ProcessDownloadedPicture(PictureBatch pb) { if (pb != null && pb.AllPictures.Any()) { this.CurrentBatch = pb; if (BatchChanging != null) { BatchChanging(pb); } //Clear the download Queue DownloadManager.ClearQueue(); List <ManualResetEvent> manualEvents = new List <ManualResetEvent>(); //call all activated output providers in order foreach (var op in Settings.CurrentSettings.ProviderSettings.Values.Where(x => x.Active && x.Instance != null).OrderBy(x => x.ExecutionOrder)) { if (!typeof(IOutputProvider).IsAssignableFrom(op.Instance.GetType())) { continue; } //wrap each in a try/catch block so we avoid killing pulse on error try { //check if this can be run in async bool asyncOK = ProviderManager.GetAsyncStatusForType(op.Instance.GetType()); IOutputProvider ip = ((IOutputProvider)op.Instance); string config = op.ProviderConfig; if (asyncOK) { ThreadStart threadStarter = () => { ManualResetEvent mre = new ManualResetEvent(false); manualEvents.Add(mre); try { ip.ProcessPicture(pb, config); } catch (Exception ex) { Log.Logger.Write(string.Format("Error processing output plugin '{0}'. Error: {1}", op.ProviderName, ex.ToString()), Log.LoggerLevels.Warnings); } finally { mre.Set(); } }; Thread thread = new Thread(threadStarter); thread.Start(); } else { ip.ProcessPicture(pb, config); } } catch (Exception ex) { Log.Logger.Write(string.Format("Error processing output plugin '{0}'. Error: {1}", op.ProviderName, ex.ToString()), Log.LoggerLevels.Errors); } } //make sure async operations finish before if (manualEvents.Count > 1) { WaitHandle.WaitAll(manualEvents.ToArray(), 60 * 1000); } else if (manualEvents.Count == 1) { manualEvents[0].WaitOne(); } if (BatchChanged != null) { BatchChanged(pb); } } }