C# 多线程的等待所有线程结束

 

//前台线程和后台线程唯一区别就是:应用程序必须运行完所有的前台线程才可以退出;
//而对于后台线程,应用程序则可以不考虑其是否已经运行完毕而直接退出,
//所有的后台线程在应用程序退出时都会自动结束。

通过匿名委托或Lambda表达式来为Thread的构造方法赋值

 Thread thread3 = new Thread(delegate() { Console.WriteLine("匿名委托"); });  
 thread3.Start();  
  
 Thread thread4 = new Thread(( ) => { Console.WriteLine("Lambda表达式"); });  
 thread4.Start();  

二、 定义一个线程类

    我们可以将Thread类封装在一个MyThread类中,以使任何从MyThread继承的类都具有多线程能力。MyThread类的代码如下:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Threading;  
namespace MyThread  
{  
   abstract class MyThread  
    {  
       Thread thread = null;  
 
       abstract public void run();      
 
        public void start()  
        {  
            if (thread == null)  
                thread = new Thread(run);  
            thread.Start();  
        }  
    }  
}

可以用下面的代码来使用MyThread类。

class NewThread : MyThread  
{  
      override public void run()  
      {  
          Console.WriteLine("使用MyThread建立并运行线程");  
      }  
  }  
 
  static void Main(string[] args)  
  {  
 
      NewThread nt = new NewThread();  
      nt.start();  
  }

   如果使用在第二节定义的MyThread类,传递参数会显示更简单,代码如下:

class NewThread : MyThread  
{  
    private String p1;  
    private int p2;  
    public NewThread(String p1, int p2)  
    {  
        this.p1 = p1;  
        this.p2 = p2;  
    }  
 
    override public void run()  
    {  
        Console.WriteLine(p1);  
        Console.WriteLine(p2);  
    }  
}  
 
NewThread newThread = new NewThread("hello world", 4321);  
newThread.start();
EventWaitHandle(等待事件句柄)

EventWaitHandle是一个在线程处理上的类,它可以和WaitHandle配合使用完成多线程任务等待调度,并且在主线程中统一处理想要的结果。

            List<string> lst = new List<string>();
            //创建等待事件句柄集合
            var watis = new List<EventWaitHandle>();
            for (int t = 0; t < 3; t++)
            {
                var handler = new ManualResetEvent(false);   //创建句柄   true终止状态
                watis.Add(handler);                          // 添加EventWaitHandle对象
                
                //线程传入参数配置,这里定义了3个参数
                var tup = new Tuple<object, List<string>, EventWaitHandle>(t, lst, handler);

                /*创建线程,传入线程参数*/
                Thread thfor = new Thread((object obj) =>
                {
                    Tuple<object, List<string>, EventWaitHandle> tupitm = (Tuple<object, List<string>, EventWaitHandle>)obj;                    
                    object Wdt = tupitm.Item1;          //传入的第一个参数 【Item1】
                    tupitm.Item2.Add("返回字符串");     //传入的第二个参数 【Item3】                  
                    tupitm.Item3.Set();                 //传入的第二个参数 【Item2】   
                });
                //启动线程
                thfor.Start(tup);
            }
            //等待句柄
            WaitHandle.WaitAll(watis.ToArray());
  • 首先创建了一个EventWaitHandle的list,这个list将用于来添加所有的需要执行的等待事件句柄

  • 然后将需要参与等待的任务(一个方法)参数化传入线程初始化的构造

  • 在线程启动时,将与之对应的EventWaitHandle子类ManualResetEvent的对象传入需要调用的任务(方法)中

  • 最后使用WaitHandle.WaitAll执行所有的等待事件句柄

  • 在等待句柄任务中执行查询,并将结果加入数据list中

  • 最后在任务的最后(执行完成)将等待事件句柄对象Set(),这个方法将发出一个信号(暂时理解为通知WaitHandle当前的等待事件句柄执行完成)

 


作者:methodname
链接:https://www.jianshu.com/p/64670b155b1c
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Lock锁

lock是一种比较好用的简单的线程同步方式,它是通过为给定对象获取互斥锁来实现同步的。它可以保证当一个线程在关键代码段的时候,另一个线程不会进来,它只能等待,等到那个线程对象被释放,也就是说线程出了临界区。

public void Function()
{
    object lockThis = new object ();
    lock (lockThis)
    {
        // Access thread-sensitive resources.
    }
}

lock关键字的用法和用途。

using System; 
using System.Threading; 
namespace ThreadSimple
{ 
    internal class Account
    { 
        int balance; //余额
        Random r=new Random(); 
        internal Account(int initial)  
        {  
            balance=initial; 
        }
        internal int Withdraw(int amount) //取回、取款
        { 
            if(balance<0) 
            {  
                //如果balance小于0则抛出异常  
                throw new Exception("NegativeBalance");//负的 余额 
            } 
            //下面的代码保证在当前线程修改balance的值完成之前 
            //不会有其他线程也执行这段代码来修改balance的值  
            //因此,balance的值是不可能小于0的  
            lock(this)  
            { 
                Console.WriteLine("CurrentThread:"+Thread.CurrentThread.Name); 
                //如果没有lock关键字的保护,那么可能在执行完if的条件判断(成立)之后  
                //另外一个线程却执行了balance=balance-amount修改了balance的值 
                //而这个修改对这个线程是不可见的,所以可能导致这时if的条件已经不成立了 
                //但是,这个线程却继续执行 balance=balance-amount,所以导致balance可能小于0 
                if(balance>=amount) 
                { 
                    Thread.Sleep(5);
                    balance=balance-amount; 
                    return  amount; 
                }  else 
                { 
                    return 0;
                    //transactionrejected 
                } 
            }  
        }
        internal void DoTransactions()//取款事务
        {
            for (int i = 0; i < 100; i++)
            {
                Withdraw(r.Next(-50, 100));
            }
        }
    }  
 

    internal class Test  
    {  
        static internal Thread[] threads=new Thread[10]; 
        public static void Main()  
        {  
            Account acc=new Account(0); 
            for(int i=0;i<10;i++) 
            {  
                Thread t=new Thread(new ThreadStart(acc.DoTransactions));
                threads[i]=t; 
            }
            for (int i = 0; i < 10; i++)
            {
                threads[i].Name = i.ToString();
            }
            for (int i = 0; i < 10; i++)
            {
                threads[i].Start();
                Console.ReadLine();
            }
        }
    } 
}
原文地址:https://www.cnblogs.com/lanyubaicl/p/11033120.html