等待线程完成

时间:2015-10-12 19:48:27

标签: c# multithreading

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

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

我尝试使用谷歌搜索答案,我说的所有答案要么使用TPL(我不能因为我使用的是.NET 3.5),要么获得对线程的引用并使用Thread.Join。但是由于线程是在另一个我没有源代码访问权限的DLL文件中创建的,所以这个选项也出来了。

我如何等待所有线程完成?

3 个答案:

答案 0 :(得分:0)

免责声明:我发布此答案只是因为它符合OP的要求而且我没有从Servy得到答案:那里有没什么可以做的。但我建议不要在生产环境中使用它。我个人会抛弃那个图书馆并自己实施。

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

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

现在,我们的想法是比较ThirdParty.DoWork调用之前和之后的正在运行的线程。在调用之后,将使用OpenThread收集一个(或多个)线程ID并将其转换为线程句柄。最后,您可以调用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不保证每个托管线程都在其自己的非托管线程上运行。

答案 1 :(得分:0)

也许您可以安装自定义CLR Profiler。这使您可以访问所有托管线程。你应该能够拦截几乎任何东西。您应该能够拦截线程启动和关闭。

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

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

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

答案 2 :(得分:-1)

鉴于您调用的异步方法未提供何时完成(Task,回调,事件等)的指示,您无需做任何事情。您总是可以使用其中一种方法将一种方法重构为一种方法,但如果核心方法没有提供何时完成的方法,那么您无法做任何事情。