示例#1
0
        public async Task RunAsync(PatchInfo[] toUpdate, PatchCache patchCache, CancellationToken ct = default)
        {
            Progress.Progress        = 0;
            Progress.IsIndeterminate = true;
            Progress.CompletedCount  = 0;
            Progress.TotalCount      = 0;

            if (toUpdate.Length == 0)
            {
                return;
            }

            var state = new ProcessState
            {
                AtomicIndex          = 0,
                AtomicCompletedCount = 0,
                AtomicProcessCount   = 0,
                UpdateBuckets        = new ConcurrentQueue <List <PatchCacheEntry> >()
            };

            var processCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ct);

            Progress.TotalCount = toUpdate.Length;

            App.Logger.Info(nameof(VerifyFilesPhase), "Starting processing threads");
            Progress.IsIndeterminate = false;
            // TODO: processor affinity?
            var threadTasks = Enumerable.Range(0, Environment.ProcessorCount)
                              .Select(i => ConcurrencyUtils.RunOnDedicatedThreadAsync(() =>
            {
                Interlocked.Increment(ref state.AtomicProcessCount);
                try
                {
                    App.Logger.Info(nameof(VerifyFilesPhase), $"Processing thread {i} started");

                    _Process(state, toUpdate, processCancellationTokenSource.Token);
                }
                catch (OperationCanceledException)
                {
                    App.Logger.Error(nameof(VerifyFilesPhase), $"Processing thread {i} canceled");
                    processCancellationTokenSource.Cancel();
                    throw;
                }
                catch (Exception ex)
                {
                    App.Logger.Error(nameof(VerifyFilesPhase), $"Exception in processing thread {i}", ex);
                    processCancellationTokenSource.Cancel();
                    throw;
                }
                finally
                {
                    Interlocked.Decrement(ref state.AtomicProcessCount);
                    App.Logger.Info(nameof(VerifyFilesPhase), $"Processing thread {i} ended");
                }
            }, $"{nameof(VerifyFilesPhase)}({i})")).ToArray();

            await Task.Run(async() =>
            {
                while (state.AtomicProcessCount > 0 || state.UpdateBuckets.Count != 0)
                {
                    await Task.Delay(250, ct);

                    Progress.Progress       = state.AtomicCompletedCount / (double)toUpdate.Length;
                    Progress.CompletedCount = state.AtomicCompletedCount;

                    if (state.UpdateBuckets.Count == 0)
                    {
                        continue;
                    }

                    while (state.UpdateBuckets.TryDequeue(out var list))
                    {
                        if (list.Count > 0)
                        {
                            await patchCache.InsertUnderTransactionAsync(list);
                        }
                    }
                }
            });

            Progress.IsIndeterminate = true;

            App.Logger.Info(nameof(VerifyFilesPhase), "Joining processing threads");
            try
            {
                await Task.WhenAll(threadTasks);
            }
            catch (Exception ex)
            {
                App.Logger.Error(nameof(VerifyFilesPhase), "Error verifying files", ex);
                throw;
            }
        }
示例#2
0
 public DiscordManager()
 {
     _DisposedTokenSource = new CancellationTokenSource();
     App.Logger.Info(nameof(DiscordManager), "Discord manager created");
     App.Current.Dispatcher.Invoke(async() => await ConcurrencyUtils.RunOnDedicatedThreadAsync(_BackgroundLoop));
 }