C#等待所有子线程执行完毕方法

本文介绍了三种确保主线程等待所有子线程执行完毕的方法:使用ManualResetEvent、判断线程池中的活动线程数量以及利用Monitor实现同步。
部署运行你感兴趣的模型镜像

当我们在使用线程中,你会发现主线结束后子线程的结果才显示出来。现在我要等待所以子线程结束,然后在显示结果,怎么做呢?

方法如下:

1、使用 ManualResetEvent,代码如下: 

复制代码
using System.Threading;

namespace ThreadStudy
{
    /// <summary>
    
/// 等待所有子线程结束
    
/// </summary>
    class StopAllWaitBySubThread
    {
        List<ManualResetEvent> manualEvents = new List<ManualResetEvent>();
        public void Main()
        {
            for (int i = 0; i < 5; i++)
            {
                ManualResetEvent mre = new ManualResetEvent(false);
                manualEvents.Add(mre);
                ThreadPool.QueueUserWorkItem(ThreadMethod, mre);
            }
            WaitHandle.WaitAll(manualEvents.ToArray());
            Console.WriteLine("Thread Finished!");
        }

        private void ThreadMethod(object obj)
        {
            //等待2秒,用于模拟系统在处理事情
            Thread.Sleep(2000);

            ManualResetEvent mre = (ManualResetEvent)obj;
            mre.Set();
            Console.WriteLine("Thread execute");
        }
    }
}
复制代码

 此种方法线程中只传递了信号,那要传递参数怎么办?可以采用类,将信号放在类中来解决,代码如下。

 

复制代码
using System.Threading;

namespace ThreadStudy
{
    /// <summary>
    
/// 等待所有子线程结束
    
/// </summary>
    class StopAllWaitBySubThread
    {
        List<ManualResetEvent> manualEvents = new List<ManualResetEvent>();
        public void Main()
        {
            for (int i = 0; i < 5; i++)
            {
                ManualResetEvent mre = new ManualResetEvent(false);
                manualEvents.Add(mre);
                Param pra = new Param();
                pra.mrEvent = mre;
                pra.praData = i;
                ThreadPool.QueueUserWorkItem(ThreadMethod, pra);
            }
            WaitHandle.WaitAll(manualEvents.ToArray());
            Console.WriteLine("Thread Finished!");
        }

        private void ThreadMethod(object obj)
        {
            Thread.Sleep(2000);
            Param pra = (Param)obj;
            pra.mrEvent.Set();
            Console.WriteLine("Thread execute at {0}", pra.praData);
        }
    }

    public class Param
    {
        public ManualResetEvent mrEvent;
        public int praData;
    }
}
复制代码

 

2、判断线程数

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;

namespace ThreadStudy
{
    /// <summary>
    
/// 判断当所有子线程执行完毕
    
/// </summary>
    class ThreadPoolStop
    {
        public void Main()
        {
            for (int i = 0; i < 5; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod), i);
            }
            int maxWorkerThreads, workerThreads;
            int portThreads;
            while (true)
            {
                /*
                 GetAvailableThreads():检索由 GetMaxThreads 返回的线程池线程的最大数目和当前活动数目之间的差值。
                 而GetMaxThreads 检索可以同时处于活动状态的线程池请求的数目。
                 通过最大数目减可用数目就可以得到当前活动线程的数目,如果为零,那就说明没有活动线程,说明所有线程运行完毕。
                 
*/
                ThreadPool.GetMaxThreads(out maxWorkerThreads, out portThreads);
                ThreadPool.GetAvailableThreads(out workerThreads, out portThreads);
                if (maxWorkerThreads - workerThreads == 0)
                {
                    Console.WriteLine("Thread Finished!");
                    break;
                }
            }
        }

        private void ThreadMethod(object i)
        {
            //模拟程序运行
            Thread.Sleep((new Random().Next(14)) * 1000);
            Console.WriteLine("Thread execute at {0}", i.ToString());
        }
    }
}
复制代码

 

 3、使用Monitor 

复制代码
using System.Threading;

namespace ThreadStudy
{
    class StopAllSubThread
    {
        int _ThreadCount = 5;
        int finishcount = 0;
        object locker = new object();
        public void Main()
        {
            for (int i = 0; i < _ThreadCount; i++)
            {
                Thread trd = new Thread(new ParameterizedThreadStart(ThreadMethod));
                trd.Start(i);
            }
            lock (locker)
            {
                while (finishcount != _ThreadCount)
                {
                    Monitor.Wait(locker);//等待
                }
            }
            Console.WriteLine("Thread Finished!");
        }

        private void ThreadMethod(object obj)
        {
            //模拟执行程序
            Thread.Sleep(3000);
            Console.WriteLine("Thread execute at {0}", obj.ToString());
            lock (locker)
            {
                finishcount++;
                Monitor.Pulse(locker); //完成,通知等待队列,告知已完,执行下一个。
            }
        }
    }
}
复制代码
转载地址:http://www.cnblogs.com/scottckt/archive/2012/01/10/2317779.html

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

### C#子线程调用 UI 界面对象的安全方法 在多线程应用程序开发中,确保从子线程安全地访问和修改 UI 组件是一个常见的需求。C# 提供了 `Invoke` 和 `BeginInvoke` 方法来实现这一目标。 #### 使用 `Invoke` 的示例 以下是基于 WPF 应用程序的一个简单例子,展示如何使用 `Invoke` 来更新 UI 控件的内容: ```csharp private void Button_Click(object sender, RoutedEventArgs e) { Thread thread = new Thread(ModifyUI); thread.Start(); } private void ModifyUI() { // 模拟耗时操作 Thread.Sleep(TimeSpan.FromSeconds(2)); // 使用 Dispatcher.Invoke 更新 UI this.Dispatcher.Invoke((Action)(() => { label1.Content = "欢迎你光临WPF的世界,Dispatcher"; })); } ``` 上述代码展示了如何通过 `Dispatcher.Invoke` 将一个委托排队到 UI 线程的消息队列中,在 UI 线程空闲时执行该委托[^2]。 #### 使用 `BeginInvoke` 的示例 与 `Invoke` 类似,`BeginInvoke` 同样可以用于跨线程的 UI 访问,但它不会阻塞当前线程直到操作完成。下面是一个 WinForms 应用中的示例: ```csharp private void UpdateUIThreadSafe(string text) { if (this.label1.InvokeRequired) { this.label1.BeginInvoke(new Action<string>(UpdateUIThreadSafe), text); } else { this.label1.Text = text; } } private void BackgroundTask() { // 模拟后台任务 Thread.Sleep(2000); string newText = "任务已完成!"; this.UpdateUIThreadSafe(newText); } ``` 在这个例子中,当检测到需要在线程间切换时,会使用 `BeginInvoke` 执行回调函数[^3]。 #### 关键点说明 - **线程安全性**:直接从非 UI 线程尝试更改 UI 元素会导致异常。这是因为大多数 GUI 工具包(如 Windows Forms 和 WPF)只允许创建这些组件的原始线程对其进行修改[^4]。 - **同步 vs 异步**:`Invoke` 是一种同步方式,它会在子线程等待直至 UI 线程处理完毕;而 `BeginInvoke` 则是非阻塞式的异步调用[^1]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值