簡體   English   中英

C#.Net-如何使應用程序等待,直到在Library中創建的所有線程完成

[英]C# .Net - How to make application wait until all threads created in Library are finished

我正在嘗試創建一個日志記錄庫,在調用應用程序關閉之前,一切都很好。 調用應用程序關閉時,所有未完成的線程都會被殺死,並且特定的日志也會丟失。

截至目前,應用程序甚至在前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.
    }
}

}

到目前為止,我自己已經找到了解決方法。

    /// <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());
    }

你可以試試

Task.WaitAll(tasks);

這等待所有提供的Task對象完成執行。

更新 :使用異步/等待

通過異步和等待,我們形式化並闡明了異步,非阻塞方法的開始和結束方式。 異步方法只能返回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}

步驟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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM