我正在尝试创建一个日志库,并且在调用应用程序关闭之前一切都很好。当调用应用程序关闭时,任何未完成的线程都会被杀死并且特定的日志会丢失。
截至目前,应用程序甚至在前 10 个线程完成之前就退出了。我需要有关如何使应用程序等到库创建的所有线程完成的帮助。
注意:我得到的要求是这样的。修改只能在“Logging”类中,因为这将是一个库并将提供给最终用户。必须在应用程序关闭期间处理日志记录问题。这就是我现在遇到麻烦的地方。
或者,像在日志记录类中创建一个事件以触发所有日志记录完成,并要求用户在该事件上调用应用程序退出这样的解决方案是可能的,但我试图避免这种情况,因为它给最终用户增加了负担并增加了实现的复杂性。他们有可能会跳过它,这是我不想要的。我正在寻找一个解决方案,比如用户应该执行 'Logging.AddException(....)' 然后忘记它。
请帮忙。如果您不清楚这个想法,请提供评论。
这是您可以放入控制台应用程序的完整代码摘要。 注意:在 CASE 1 和 CASE 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.
}
}
}