2

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

現在、アプリケーションは最初の 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.
    }
}

}

4

3 に答える 3

1

あなたが試すことができます

Task.WaitAll(tasks);

これは、提供されたすべての Task オブジェクトの実行が完了するまで待機します。

UPDATE : async/await の使用

async と await を使用して、非同期のノンブロッキング メソッドがどのように開始および終了するかを形式化し、明確にします。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}
于 2015-11-02T21:02:23.517 に答える
0

ステップ 1: スケジューラーを関与させたくない場合は、Task.Run() への変更を検討してください。また、すべての非同期タスクが完了するまで待ちたいと思っていると思います。

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();
于 2015-11-02T21:19:50.487 に答える