如何让我的方法等待所有线程完成?

2024-05-03

我有一个方法可以触发线程来完成一些工作。将有 2 个线程异步运行一段时间,当调用它们的回调方法时,回调会触发另一个线程,直到所有工作完成。如何让我的方法等待所有这些线程完成并被触发?


如果这是 .Net 4.0,您可以使用CountdownEvent http://msdn.microsoft.com/en-us/library/system.threading.countdownevent.aspx

const int threads = 10;
using( CountdownEvent evt = new CountdownEvent(threads) )
{
    for( int x = 0; x < threads; ++x )
    {
        ThreadPool.QueueUserWorkItem((state) =>
            {
                // Do work here
                ((CountdownEvent)state).Signal();
            }, evt);
    }

    evt.Wait();
}
Console.WriteLine("Everyone finished!");

这样做的优点是工作时Thread.Join不是一个选项(例如,如果您使用线程池),并且比使用等待句柄更好地扩展(因为WaitHandle.WaitAll最多有 64 个句柄,并且您也不需要分配那么多对象)。

请注意,如果您使用 .Net 4,您还可以使用任务并行库,这使此类事情变得更容易。

Update:

既然你说这不是 .Net 4.0,那么这里是一个简单版本CountdownEvent可以在.Net 3.5 中使用。我最初编写它是因为我需要一个可以在 Mono 中使用的 CountdownEvent,当时 Mono 还不支持 .Net 4。它不像真正的那样灵活,但它可以满足您的需要:

/// <summary>
/// Represents a synchronization primitive that is signaled when its count reaches zero.
/// </summary>
/// <remarks>
/// <para>
///   This class is similar to but less versatile than .Net 4's built-in CountdownEvent.
/// </para>
/// </remarks>
public sealed class CountdownEvent : IDisposable
{
    private readonly ManualResetEvent _reachedZeroEvent = new ManualResetEvent(false);
    private volatile int _count;
    private volatile bool _disposed;

    /// <summary>
    /// Initializes a new instance of the <see cref="CountdownEvent"/> class.
    /// </summary>
    /// <param name="initialCount">The initial count.</param>
    public CountdownEvent(int initialCount)
    {
        _count = initialCount;
    }

    // Disable volatile not treated as volatile warning.
#pragma warning disable 420

    /// <summary>
    /// Signals the event by decrementing the count by one.
    /// </summary>
    /// <returns><see langword="true" /> if the count reached zero and the event was signalled; otherwise, <see langword="false"/>.</returns>
    public bool Signal()
    {
        CheckDisposed();

        // This is not meant to prevent _count from dropping below zero (that can still happen due to race conditions),
        // it's just a simple way to prevent the function from doing unnecessary work if the count has already reached zero.
        if( _count <= 0 )
            return true;

        if( Interlocked.Decrement(ref _count) <= 0 )
        {
            _reachedZeroEvent.Set();
            return true;
        }
        return false;
    }

#pragma warning restore 420

    /// <summary>
    /// Blocks the calling thread until the <see cref="CountdownEvent"/> is set.
    /// </summary>
    public void Wait()
    {
        CheckDisposed();
        _reachedZeroEvent.WaitOne();
    }

    /// <summary>
    /// Blocks the calling thread until the <see cref="CountdownEvent"/> is set, using a <see cref="TimeSpan"/> to measure the timeout.
    /// </summary>
    /// <param name="timeout">The timeout to wait, or a <see cref="TimeSpan"/> representing -1 milliseconds to wait indefinitely.</param>
    /// <returns><see langword="true"/> if the <see cref="CountdownEvent"/> was set; otherwise, <see langword="false"/>.</returns>
    public bool Wait(TimeSpan timeout)
    {
        CheckDisposed();
        return _reachedZeroEvent.WaitOne(timeout, false);
    }

    /// <summary>
    /// Blocks the calling thread until the <see cref="CountdownEvent"/> is set, using a 32-bit signed integer to measure the timeout.
    /// </summary>
    /// <param name="millisecondsTimeout">The timeout to wait, or <see cref="Timeout.Infinite"/> (-1) to wait indefinitely.</param>
    /// <returns><see langword="true"/> if the <see cref="CountdownEvent"/> was set; otherwise, <see langword="false"/>.</returns>
    public bool Wait(int millisecondsTimeout)
    {
        CheckDisposed();
        return _reachedZeroEvent.WaitOne(millisecondsTimeout, false);
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        if( !_disposed )
        {
            if( disposing )
                ((IDisposable)_reachedZeroEvent).Dispose();
            _disposed = true;
        }
    }

    private void CheckDisposed()
    {
        if( _disposed )
            throw new ObjectDisposedException(typeof(CountdownEvent).FullName);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何让我的方法等待所有线程完成? 的相关文章

  • 访问私人成员[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 通过将类的私有成员转换为 void 指针 然后转换为结构来访问类的私有成员是否合适 我认为我无权修改包含我需要访问的数据成员的类 如果不道德 我
  • 如何在列表框项目之间画一条线

    我希望能够用水平线分隔列表框中的每个项目 这只是我用于绘制项目的一些代码 private void symptomsList DrawItem object sender System Windows Forms DrawItemEvent
  • 为什么#pragma optimize("", off)

    我正在审查一个 C MFC 项目 在某些文件的开头有这样一行 pragma optimize off 我知道这会关闭所有以下功能的优化 但这样做的动机通常是什么 我专门使用它来在一组特定代码中获得更好的调试信息 并在优化的情况下编译应用程序
  • 获取没有非标准端口的原始 url (C#)

    第一个问题 环境 MVC C AppHarbor Problem 我正在调用 openid 提供商 并根据域生成绝对回调 url 在我的本地机器上 如果我点击的话 效果很好http localhost 12345 login Request
  • C 预处理器库

    我的任务是开发源分析工具C程序 并且我需要在分析本身之前预处理代码 我想知道什么是最好的图书馆 我需要一些重量轻 便于携带的东西 与其推出自己的 为什么不使用cpp这是的一部分gcc suite http gcc gnu org onlin
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • for循环中计数器变量的范围是多少?

    我在 Visual Studio 2008 中收到以下错误 Error 1 A local variable named i cannot be declared in this scope because it would give a
  • Qt表格小部件,删除行的按钮

    我有一个 QTableWidget 对于所有行 我将一列的 setCellWidget 设置为按钮 我想将此按钮连接到删除该行的函数 我尝试了这段代码 它不起作用 因为如果我只是单击按钮 我不会将当前行设置为按钮的行 ui gt table
  • clang 实例化后静态成员初始化

    这样的代码可以用 GCC 编译 但 clang 3 5 失败 include
  • 从库中捕获主线程 SynchronizationContext 或 Dispatcher

    我有一个 C 库 希望能够将工作发送 发布到 主 ui 线程 如果存在 该库可供以下人员使用 一个winforms应用程序 本机应用程序 带 UI 控制台应用程序 没有 UI 在库中 我想在初始化期间捕获一些东西 Synchronizati
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • 32 位到 64 位内联汇编移植

    我有一段 C 代码 在 GNU Linux 环境下用 g 编译 它加载一个函数指针 它如何执行并不重要 使用一些内联汇编将一些参数推送到堆栈上 然后调用该函数 代码如下 unsigned long stack 1 23 33 43 save
  • 为什么 C# Math.Ceiling 向下舍入?

    我今天过得很艰难 但有些事情不太对劲 在我的 C 代码中 我有这样的内容 Math Ceiling decimal this TotalRecordCount this PageSize Where int TotalRecordCount
  • Process.Start 阻塞

    我正在调用 Process Start 但它会阻止当前线程 pInfo new ProcessStartInfo C Windows notepad exe Start process mProcess new Process mProce
  • const、span 和迭代器的问题

    我尝试编写一个按索引迭代容器的迭代器 AIt and a const It两者都允许更改容器的内容 AConst it and a const Const it两者都禁止更改容器的内容 之后 我尝试写一个span
  • x86 上未对齐的指针

    有人可以提供一个示例 将指针从一种类型转换为另一种类型由于未对齐而失败吗 在评论中这个答案 https stackoverflow com questions 544928 reading integer size bytes from a
  • mysql-connector-c++ - “get_driver_instance”不是“sql::mysql”的成员

    我是 C 的初学者 我认为学习的唯一方法就是接触一些代码 我正在尝试构建一个连接到 mysql 数据库的程序 我在 Linux 上使用 g 没有想法 我运行 make 这是我的错误 hello cpp 38 error get driver
  • ASP.NET MVC 6 (ASP.NET 5) 中的 Application_PreSendRequestHeaders 和 Application_BeginRequest

    如何在 ASP NET 5 MVC6 中使用这些方法 在 MVC5 中 我在 Global asax 中使用了它 现在呢 也许是入门班 protected void Application PreSendRequestHeaders obj
  • 如何在 C++ BOOST 中像图形一样加载 TIFF 图像

    我想要加载一个 tiff 图像 带有带有浮点值的像素的 GEOTIFF 例如 boost C 中的图形 我是 C 的新手 我的目标是使用从源 A 到目标 B 的双向 Dijkstra 来获得更高的性能 Boost GIL load tiif
  • 限制C#中的并行线程数

    我正在编写一个 C 程序来生成并通过 FTP 上传 50 万个文件 我想并行处理4个文件 因为机器有4个核心 文件生成需要更长的时间 是否可以将以下 Powershell 示例转换为 C 或者是否有更好的框架 例如 C 中的 Actor 框

随机推荐