0

Я пытаюсь создать библиотеку протоколирования, и все будет хорошо, пока не вызывается выключение приложения. Когда вызывается выключение приложения, любой незавершенный поток убивается, а конкретный журнал теряется.C# .Net - Как сделать приложение до тех пор, пока все потоки, созданные в Библиотеке, не будут завершены.

В настоящее время приложение выходит даже до завершения первых 10 потоков. Мне нужна помощь в том, как заставить приложение ждать, пока все потоки, созданные библиотекой, не будут выполнены.

ПРИМЕЧАНИЕ: Требование, которое я получил, такое. Изменения должны быть только в классе «Регистрация», поскольку это будет библиотека и будет предоставлена ​​конечным пользователям. В этом случае необходимо выполнить обработку проблем с журналом при отключении приложения. Здесь у меня проблемы.

В качестве альтернативы решение, например, создать событие в классе ведения журнала, чтобы вызвать полное завершение ведения журнала, и попросить пользователя вызвать выход приложения на это событие, возможно, но этого я стараюсь избегать, поскольку он добавляет эту нагрузку для конечного пользователя и добавляет сложность реализации. Есть вероятность, что они могут пропустить это, чего я не хочу. Я ищу решение, как пользователь должен сделать «Logging.AddException (....)», а затем забудьте об этом.

Пожалуйста, помогите. Предоставьте комментарии, если вы не совсем поняли эту идею.

Вот полный текст, который вы можете добавить в консольное приложение. Примечания: Посмотрите на комментарии в случае 1 и СЛУЧАЕ 2.

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 

namespace MultithreadKeepAlive 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 
     LogLoadTest(); 
     Logging.AddExceptionEntryAsync(new Exception("Last Exception")); 

     /* 
     * USE CASE 1: Enable the below lines and you will see how long it is supposed to take. 
     * Notice that currentDomain_ProcessExit will not trigger if below gets uncommented 
     */ 
     //Console.WriteLine("Main thread wait override"); 
     //Console.ReadLine(); 
    } 

    static void LogLoadTest() 
    { 
     //In real world this will be called from any place of application like startup or just after application shutdown is initiated. 
     //: NOTICE: Unlike the sample here, this will never be on loop and I am not looking for handling multithreads in this class. 
     //  That responsibility I am planning to assign to Logging class. 
     // AND ALSO the class Logging is going to be in a seperate signed assembly where user of this class ('Program') should not worry about multithreads. 
     Task t; 
     for (int i = 0; i < 40; i++) 
     { 
      t = Logging.AddExceptionEntryAsync(new Exception("Hello Exception " + i), "Header info" + i); 
     } 
    } 
} 

public class Logging 
{ 
    static List<Task> tasks = new List<Task>(); 

    static AppDomain currentDomain; 
    static Logging() 
    { 
     currentDomain = AppDomain.CurrentDomain; 
     currentDomain.ProcessExit += currentDomain_ProcessExit; 
    } 

    public static async Task AddExceptionEntryAsync(Exception ex, string header = "") 
    { 
     Task t = Task.Factory.StartNew(() => AddExceptionEntry(ex, header)); 
     tasks.Add(t); 
     await t; 
    } 

    public static void AddExceptionEntry(Exception ex, string header) 
    { 
     /* Exception processing and write to file or DB. This might endup in file locks or 
     * network or any other cases where it will take delays from 1 sec to 5 minutes. */ 
     Thread.Sleep(new Random().Next(1, 1000)); 
     Console.WriteLine(ex.Message); 
    } 

    static void currentDomain_ProcessExit(object sender, EventArgs e) 
    { 
      Console.WriteLine("Application shutdown triggerd just now."); 
      Process.GetCurrentProcess().WaitForExit(); //1st attempt. 
      //Task.WaitAll(tasks.ToArray()); //2nd attempt 
      while (tasks.Any(t => !t.IsCompleted)) //3rd attempt. 
      { 
      } 
      /* USE CASE 2: IF WORKING GOOD, THIS WILL BE DISPLAYED IN CONSOLE AS LAST 
      * MESSAGE OF APPLICATION AND WILL WAIT FOR USER. THIS IS NOT WORKING NOW.*/ 
      Console.WriteLine("All complete"); //this message should show up if this work properly 
      Console.ReadLine(); //for testing purpose wait for input from user after every thread is complete. Check all 40 threads are in console. 
    } 
} 

}

+0

Пробовал это с помощью функции нити join()? Если вы выходите, вы можете вызвать метод для каждого работающего потока. Таким образом, программа ждет, пока они не закончатся. –

+0

Почему эта функция: 'AddExceptionEntryAsync (Exception ex, string header)' не помечена 'async' и просто использует' Task.Delay' внутри нее? Прочитали ли вы документацию по ['Process.Exit'] (https://msdn.microsoft.com/en-us/library/system.appdomain.processexit (v = vs.110) .aspx)? В частности, эта часть * «Общее время выполнения всех обработчиков событий ProcessExit ограничено, так же как ** полное время выполнения всех финализаторов ограничено при завершении процесса.Значение по умолчанию - две секунды **. Неуправляемый хост может изменить это время выполнения, вызвав метод со значением перечисления. »* –

+0

Рон Бейер, lorenz albert: все они пробовали. Они работают в нормальных сценариях, где приложение работает как обычно. Здесь, когда закрытие приложения ничего не мешает ему убить все темы, которые я пробовал, уничтожаются, а приложение существует без записи журналов. –

ответ

1

В настоящее время я сам нашел обходной путь.

/// <summary> 
    /// Makes the current thread Wait until any of the pending messages/Exceptions/Logs are completly written into respective sources. 
    /// Call this method before application is shutdown to make sure all logs are saved properly. 
    /// </summary> 
    public static void WaitForLogComplete() 
    { 
     Task.WaitAll(tasks.Values.ToArray()); 
    } 
0

Вы можете попробовать

Task.WaitAll(tasks); 

Это ждет все предоставленную задачи объектов для завершения выполнения.

UPDATE: с помощью асинхр/ждут

с асинхронным и ждать, мы формализовать и разъяснить, как асинхронные нелипкие методы начинаются и заканчиваются. Метод async может возвращать только void или Task.

static void Main() 
{ 
// Create task and start it. 
// ... Wait for it to complete. 
Task task = new Task(AsyncMethod); 
task.Start(); 
task.Wait(); 
} 

public static async void AsyncMethod(){ 
await AnotherMehod();} 

static async Task AnotherMehod() { //TODO} 
+0

Rejeb: Это полезно, если приложение работает как обычно. Моя проблема в том, что он будет убит, когда приложение выйдет. Я хочу сохранить приложение в активном состоянии, пока потоки не будут выполнены. –

+0

@digitally_inspired Я обновил свой ответ с помощью async/await –

+0

не помог .. это невозможно сделать в библиотеке ... –

0

Шаг 1: Рассмотрите возможность изменения на Task.Run(), если вы не хотите, чтобы планировщик был вовлечен. Я также предполагаю, что вы хотите дождаться завершения всех задач async.

public static AddExceptionEntry(Exception ex, string header = "") 
{ 
    Task t = Task.Factory.StartNew(() => AddExceptionEntry(ex, header)); 
    tasks.Add(t); 

    WaitForExecutionAsync().ConfigureAwait(true); 
} 

public static async Task WaitForExecutionAsync() 
{ 
    if(tasks.Count >0) 
     await Task.WhenAll(tasks.ToArray()); 
    // Raise Event. 
} 

Для блока просто называем это запустить синхронизацию против асинхронного:

WaitForExecution().GetAwaiter().GetResult(); 
+0

Шаг1 Я предполагаю, что это изменение. Задача t = Задача. Run (() => AddExceptionEntryAsync (ex, header)); // Задача t = Задача.Factory.StartNew (() => AddExceptionEntryAsync (ex, header)); tasks.Add (t); Next one WaitForExecution() .. где, по вашему мнению, это нужно назвать? –

+0

Является ли AddExceptionEntry для вызова моих нескольких потоков, и в этом причина, чтобы сохранить список задач и ждать выполнения? – Kentonbmax

+0

Да, он будет вызываться из любой части приложения в любое время. и в случае закрытия приложения он должен иметь возможность закончить работу, не убившись! –