/// <summary> /// Отменить текущее выполнение операции /// </summary> /// <param name="obj">Объект операции</param> /// <exception cref="System.ArgumentNullException" /> /// <exception cref="System.InvalidOperationException" /> /// <exception cref="System.ArgumentException" /> /// <exception cref="System.AggregateException" /> public void Cancel(OperationObject obj) { if (obj == null) { throw new ArgumentNullException("obj"); } Cancel(obj.OperationId); }
/// <summary> /// Запуск последовательно /// </summary> /// <param name="operation"></param> /// <returns></returns> private OperationObject RunSerial(ICompositeOperation operation) { var operations = operation.GetOperations(); if (operations == null || operations.Length == 0) { throw new ArgumentException("No any operation to run ", "consequentOperations"); } // Инициализация int n = operations.Length; var tokenSource = new CancellationTokenSource(); var commonState = new InteropState(); var mockOperationObj = new OperationObject { OperationId = GetNewIndex() }; var mockInterop = new OperationInterop(mockOperationObj, tokenSource.Token, commonState); OperationObject[] conseqOperationObjects = new OperationObject[n]; // Создание объектов представления операций for (int i = 0; i < n; ++i) { conseqOperationObjects[i] = new OperationObject { Parent = mockOperationObj }; mockOperationObj.Children.Add(conseqOperationObjects[i]); } Task chainEnd = null; Task firstTask = null; bool finalSet = false; // Создание цепочки выполнения for (int i = 0; i < n; ++i) { // --> Переменные для замыкания var j = i; var thisOperation = operations[i]; var thisOperationObj = conseqOperationObjects[i]; var thisInterop = new OperationInterop(thisOperationObj, tokenSource.Token, commonState); // <-- thisOperationObj.OperationId = GetNewIndex(); thisOperationObj.Name = thisOperation.OperationInfo.Name; // Chain :: Выполнение операции if (chainEnd == null) { // Первая операция chainEnd = new Task(() => { mockOperationObj.Status = OperationStatus.Running; operation.OnChainStart(mockInterop); thisOperation.Execute(thisInterop); }, tokenSource.Token); firstTask = chainEnd; } else { // Цепляем следующие chainEnd = chainEnd.ContinueWith((_, __) => { tokenSource.Token.ThrowIfCancellationRequested(); thisOperation.Execute(thisInterop); }, null, tokenSource.Token, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current); } // Chain :: Обработка законченной операции chainEnd = chainEnd.ContinueWith(et => { thisOperation.Dispose(); // Установка статуса собственной операции thisOperationObj.Status = et.Status.ToOperationStatus(); // Установка статуса главной репрезентативной операции if (!finalSet) { if (et.Status != TaskStatus.RanToCompletion) { // Любая операция завершилась неуспешно mockOperationObj.Status = et.Status.ToOperationStatus(); thisOperationObj.Exception = et.Exception; mockOperationObj.Exception = et.Exception; if (!IsBeingWatched(mockOperationObj)) { Notifier.Notify("Операция #" + mockOperationObj.OperationId, "Операция не завершена", null); } tokenSource.Cancel(); finalSet = true; } else if (j == n - 1) { // Последняя операция завершилась успешно mockOperationObj.Status = OperationStatus.RanToCompletion; mockOperationObj.Progress = 100; if (!IsBeingWatched(mockOperationObj)) { Notifier.Notify("Операция #" + mockOperationObj.OperationId, "Операция завершена", null); } tokenSource.Cancel(); finalSet = true; } } if (j < n - 1) { // Установка прогресса главной репрезентативной операции UpdateMockOperationProgress(mockOperationObj, n, j + 1); } }); thisOperationObj.Status = OperationStatus.Created; } chainEnd.ContinueWith(t => { operation.OnChainEnded(); operation.Dispose(); }); // Обработка и запуск выполнения цепочки mockOperationObj.Status = OperationStatus.Created; mockOperationObj.Added = DateTime.Now; mockOperationObj.Name = operation.OperationInfo.Name; AddOperation(mockOperationObj); AddUnit(mockOperationObj.OperationId, new OperationUnit { CancellationTokenSource = tokenSource, ChainEndTask = chainEnd }, operations); firstTask.Start(); return mockOperationObj; }
private void UpdateMockOperationProgress(OperationObject obj, int childrenCount, int finishedCount) { if (finishedCount < childrenCount) { if (finishedCount > 0) { var ratio = (float)finishedCount / (float)childrenCount; var percents = Convert.ToInt32(Math.Round(ratio, 2) * 100); obj.Progress = percents; } } }
/// <summary> /// Удалить указанный объект представления операции из списка /// </summary> /// <param name="obj">Объект представления операции</param> private void RemoveOperation(OperationObject obj) { lock (operationsList_lock) { operationsList.Remove(obj); } }
/// <summary> /// Запуск параллельно /// </summary> /// <param name="operation"></param> /// <returns></returns> private OperationObject RunParallel(ICompositeOperation operation) { var operations = operation.GetOperations(); if (operations == null || operations.Length == 0) { throw new ArgumentException("No any operation to run ", "consequentOperations"); } // Инициализация int n = operations.Length; var tokenSource = new CancellationTokenSource(); var commonState = new InteropState(); var mockOperationObj = new OperationObject { OperationId = GetNewIndex() }; var mockInterop = new OperationInterop(mockOperationObj, tokenSource.Token, commonState); OperationObject[] parallelOperationObjects = new OperationObject[n]; // Создание объектов представления операций for (int i = 0; i < n; ++i) { parallelOperationObjects[i] = new OperationObject { Parent = mockOperationObj }; mockOperationObj.Children.Add(parallelOperationObjects[i]); } List<Task> tasks = new List<Task>(); int finishedCount = 0; bool totalSuccess = true; bool canceled = false; // Создание цепочки выполнения for (int i = 0; i < n; ++i) { // текущая задача Task task = null; // --> Переменные для замыкания var j = i; var thisOperation = operations[i]; var thisOperationObj = parallelOperationObjects[i]; var thisInterop = new OperationInterop(thisOperationObj, tokenSource.Token, commonState); // <-- thisOperationObj.OperationId = GetNewIndex(); thisOperationObj.Name = thisOperation.OperationInfo.Name; // Запуск операции task = new Task(() => { thisOperationObj.Status = OperationStatus.Running; thisOperation.Execute(thisInterop); }, tokenSource.Token); // Обработка законченной операции task.ContinueWith(et => { thisOperation.Dispose(); finishedCount++; // Установка статуса собственной операции thisOperationObj.Status = et.Status.ToOperationStatus(); if (et.Status != TaskStatus.RanToCompletion) { thisOperationObj.Exception = et.Exception; totalSuccess = false; if (et.Status == TaskStatus.Canceled) { canceled = true; tokenSource.Cancel(); } } // Установка прогресса главной репрезентативной операции UpdateMockOperationProgress(mockOperationObj, n, finishedCount); // завершились все задачи // Установка статуса главной репрезентативной операции if (finishedCount == n) { if (totalSuccess) { // Последняя операция завершилась успешно mockOperationObj.Status = OperationStatus.RanToCompletion; mockOperationObj.Progress = 100; if (!IsBeingWatched(mockOperationObj)) { Notifier.Notify("Операция #" + mockOperationObj.OperationId, "Операция завершена", null); } } else { mockOperationObj.Status = canceled ? OperationStatus.Canceled : OperationStatus.Faulted; if (!IsBeingWatched(mockOperationObj)) { Notifier.Notify("Операция #" + mockOperationObj.OperationId, "Операция не завершена", null); } } tokenSource.Cancel(); operation.OnChainEnded(); operation.Dispose(); } }); thisOperationObj.Status = OperationStatus.Created; tasks.Add(task); } // Обработка и запуск выполнения цепочки mockOperationObj.Status = OperationStatus.Created; mockOperationObj.Added = DateTime.Now; mockOperationObj.Name = operation.OperationInfo.Name; AddOperation(mockOperationObj); AddUnit(mockOperationObj.OperationId, new OperationUnit { CancellationTokenSource = tokenSource }, operations); operation.OnChainStart(mockInterop); mockOperationObj.Status = OperationStatus.Running; foreach (Task task in tasks) { task.Start(); } return mockOperationObj; }
/// <summary> /// Находится ли объект представления операции под наблюдением /// </summary> /// <param name="obj">Объект представления операции</param> /// <returns>Статус нахождения объекта под наблюдением</returns> private bool IsBeingWatched(OperationObject obj) { return watchOperations.Contains(obj); }
/// <summary> /// Добавить объект представления операции в список /// </summary> /// <param name="obj">Объект представления операции</param> private void AddOperation(OperationObject obj) { lock (operationsList_lock) { operationsList.Add(obj); } }
/// <summary> /// Добавить объект представления в список наблюдения. /// Уведомления об операциях, чьи объекты представления находятся под наблюдением, не всплывают /// </summary> /// <param name="obj">Объект представления операции</param> public void Watch(OperationObject obj) { if (!watchOperations.Contains(obj)) { watchOperations.Add(obj); } }
/// <summary> /// Убрать объект представления из списка наблюдения. /// Для операции, чей объект представления не находится под наблюдением, всплывают уведомления /// </summary> /// <param name="obj">Объект представления операции</param> public void Unwatch(OperationObject obj) { if (watchOperations.Contains(obj)) { watchOperations.Remove(obj); } }
/// <summary> /// Запустить одну операцию /// </summary> /// <param name="operation">Операция</param> /// <exception cref="System.ArgumentNullException" /> public OperationObject Run(IOperation operation) { if (operation == null) { throw new ArgumentNullException("operation"); } // Инициализация var tokenSource = new CancellationTokenSource(); var operationObj = new OperationObject { OperationId = GetNewIndex() }; var interop = new OperationInterop(operationObj, tokenSource.Token); // Chain :: Выполнение операции var task = new Task(() => { operationObj.Status = OperationStatus.Running; operation.Execute(interop); }, tokenSource.Token); // Chain :: Обработка законченной операции var chainEnd = task.ContinueWith(et => { operationObj.Exception = et.Exception; operationObj.Status = et.Status.ToOperationStatus(); operationObj.Progress = 100; operation.Dispose(); if (!IsBeingWatched(operationObj)) { Notifier.Notify("Операция #" + operationObj.OperationId, "Операция завершена", null); } }); // Обработка и запуск цепочки выполнения AddOperation(operationObj); AddUnit(operationObj.OperationId, new OperationUnit { CancellationTokenSource = tokenSource, ChainEndTask = chainEnd }, operation); operationObj.Status = OperationStatus.Created; operationObj.Name = operation.OperationInfo.Name; task.Start(); return operationObj; }