等待线程完成

本文关键字:线程 等待 | 更新日期: 2023-09-27 18:17:16

我有一个c#程序,它调用几个函数,每个函数调用另一个DLL中的方法。这个方法创建一个新线程来完成它的工作,然后立即返回。

问题是我需要我的主程序等待所有未完成的线程完成。我怎样才能做到这一点呢?

我试着在谷歌上搜索答案,我得到的所有答案都说要么使用TPL(我不能,因为我使用。net 3.5),要么引用线程并使用Thread.Join。但是由于线程是在另一个DLL文件中创建的,我没有源代码访问,所以这个选项也不存在。

如何等待所有线程完成?

等待线程完成

免责声明:我发布这个答案只是因为它做了OP要求的,我没有从Servy得到答案:没有什么可以做的。但是我建议不要在生产环境中使用它。就我个人而言,我会放弃这个库并自己实现它。

也就是说,作为测试,我创建了一个类库,其中包含一个方法DoWork,该方法启动一个运行10秒的后台线程:

public class ThirdParty
{
    public static void DoWork()
    {
        new Thread(() => Thread.Sleep(10000)) { IsBackground = true }.Start();
    }
}

现在,我们的想法是比较ThirdParty.DoWork调用前后正在运行的线程。调用之后,将收集一个(或多个)线程id,并使用OpenThread将其转换为线程句柄。最后,你可以调用WaitForMultipleObjects来等待第三方后台线程完成它的工作。

class Program
{
    [DllImport("kernel32.dll")]
    static extern uint WaitForMultipleObjects(int nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds);
    [DllImport("kernel32.dll")]
    static extern IntPtr OpenThread(uint dwDesiredAccess, bool bInheritHandle, int dwThreadId);
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool CloseHandle(IntPtr hObject);
    const uint SYNCHRONIZE = 0x00100000;
    static IntPtr GetThreadHandleById(int threadId)
    {
        return OpenThread(SYNCHRONIZE, false, threadId);
    }
    static void Main(string[] args)
    {
        var threads = new List<int>();
        foreach (ProcessThread thread in Process.GetCurrentProcess().Threads)
            threads.Add(thread.Id);
        ThirdParty.DoWork();
        var threadHandlesToWaitFor = new List<IntPtr>();
        foreach (ProcessThread thread in Process.GetCurrentProcess().Threads)
            if (!threads.Contains(thread.Id))
                threadHandlesToWaitFor.Add(GetThreadHandleById(thread.Id));
        Console.WriteLine("Waiting for {0} thread(s) to finish...", threadHandlesToWaitFor.Count);
        WaitForMultipleObjects(threadHandlesToWaitFor.Count, threadHandlesToWaitFor.ToArray(), true, 0xffffffff);
        foreach (var handle in threadHandlesToWaitFor)
            CloseHandle(handle);
    }
}

本质上,我们正在等待一个非托管线程,它似乎正在运行派生的托管线程。这在将来可能会中断,因为。net不能保证每个托管线程都运行在自己的非托管线程上。

也许你可以安装一个自定义的CLR分析器。这样就可以访问所有托管线程。你应该能截获任何东西。你应该能够拦截线程的启动和关闭。

CLR Profiler API被SQL Server和ASP等主机使用。.NET对托管的。NET代码执行极具侵入性的监视和行为更改。

作为最后的手段,你甚至可以使用Profiler API来运行时重写该库的IL…

这是一种可靠的方法,但可能不容易或快速完成

考虑到您正在调用的异步方法没有提供何时完成的指示(Task,回调,事件等),您没有什么可做的。您总是可以使用其中一种方法将方法重构为另一种方法,但是如果核心方法没有提供何时完成的指示,那么您就无能为力了。