ログ ライブラリを作成しようとしていますが、アプリケーションのシャットダウンが呼び出されるまで問題はありません。アプリケーションのシャットダウンが呼び出されると、未完了のスレッドが強制終了され、特定のログが失われます。
現在、アプリケーションは最初の 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.
}
}
}