.NET AutoResetEvent ManualResetEvent 信号机制以及Semaphore

1.当多个线程在等待一个 AutoResetEvent的时候,每次调用AutoResetEvent.Set()方法只会唤醒一个线程
2.当多个线程在等待一个ManualResetEvent的时候,每次调用ManualResetEvent.Set()方法会唤醒所有等待的线程
3.当多个线程在等待一个Semaphore的时候,每次调用Semaphore.Release(Int releaseCount)的时候 将唤醒releaseCount个线程
如果调用的是Semaphore.Release() 那么相当于Semaphore.Release(1);
4.AutoResetEvent可以多次调用 Set方法,而Semaphore在每次被调用Release方法的时候会计数,如果这个数字超过了最大限制 ,那么会抛出一个SemaphoreFullException(最大数值可以在构造函数中确定 maximumCount)

AutoResetEvent 和 ManualResetEvent 都是继承 EventWaitHandle : WaitHandle
Semaphore也继承WaitHandle
其中常用的就是WaitOne()
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
AutoResetEvent 允许线程通过发信号互相通信。通常,此通信涉及线程需要独占访问的资源。

线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号。如果 AutoResetEvent 处于非终止状态,则该线程阻塞,并等待当前控制资源的线程通过调用 Set 发出资源可用的信号。
{AutoResetEvent art=new AutoResetEvent (false);//阻碍线程,等待信号发送{art.set()}。}
调用 Set 向 AutoResetEvent 发信号以释放等待线程。AutoResetEvent 将保持终止状态,直到一个正在等待的线程被释放,然后自动返回非终止状态。如果没有任何线程在等待,则状态将无限期地保持为终止状态。可以通过将一个布尔值传递给构造函数来控制 AutoResetEvent 的初始状态,如果初始状态为终止状态,则为 true(有信号状态‌);否则为 false(无信号状态)。

AutoResetEvent初始化时,参数设置表示其第一次的使用是否已经是阻塞状态,true表示线程不等待,false表示线程需要等待
每次调用AutoResetEvent的set方法将只会释放一个被阻止的线程,不会同时释放所有被此阻塞的线程。
AutoResetEvent的waitone方法不带参数将无休止等待一个被释放的信号,直到收到信号才继续执行。
带参数表示使用的参数为等待的时间,在等待时间内收到释放信号将返回一个true并继续执行,在参数设定的时间内没收到信号将返回false并继续向下执行。

通俗的来讲只有等myResetEven.Set()成功运行后,myResetEven.WaitOne()才能够获得运行机会;Set是发信号,WaitOne是等待信号,只有发了信号,等待的才会执行。如果不发的话,WaitOne后面的程序就永远不会执行。
ManualResetEvent 将保持终止状态(即对 WaitOne 的调用的线程将立即返回,并不阻塞),直到它被手动重置。可以通过将布尔值传递给构造函数来控制 ManualResetEvent 的初始状态,如果初始状态处于终止状态,为 true;否则为 false。
AutoResetEvent:开启 执行 关闭 {自动控制。每次都只能一个线程运行,立即关闭,其它等待信号} 在发送完信号后会立即置为false,等待信号
ManualResetEvenet:开启 执行 执行 执行 {不阻塞},关闭 {是人工控制}
不同的地方就在于AutoResetEvent的WaitOne()方法执行后会自动又将信号置为不发送状态也就是阻塞状态,当再次遇到WaitOne()方法是又会被阻塞,
而ManualResetEvent则不会,只要线程处于非阻塞状态则无论遇到多少次WaitOne()方法都不会被阻塞,除非调用ReSet()方法来手动阻塞线程。

在这里插入图片描述

class MREDemo
    {
        private ManualResetEvent _mre;

        public MREDemo()
        {
            this._mre = new ManualResetEvent(true);
        }

        public void CreateThreads()
        {
            Thread t1 = new Thread(new ThreadStart(Run));
            t1.Start();

            Thread t2 = new Thread(new ThreadStart(Run));
            t2.Start();
        }

        public void Set()
        {
            this._mre.Set();
        }

        public void Reset()
        {
            this._mre.Reset();
        }

        private void Run()
        {
            string strThreadID = string.Empty;
            try
            {
                while (true)
                {
                    // 阻塞当前线程
                    this._mre.WaitOne();

                    strThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
                    Console.WriteLine("Thread(" + strThreadID + ") is running...");

                    Thread.Sleep(5000);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("线程(" + strThreadID + ")发生异常!错误描述:" + ex.Message.ToString());
            }
        }

    }


    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine("****************************");
            Console.WriteLine("输入\"stop\"停止线程运行...");
            Console.WriteLine("输入\"run\"开启线程运行...");
            Console.WriteLine("****************************\r\n");

            MREDemo objMRE = new MREDemo();
            objMRE.CreateThreads();

            while (true)
            {
                string input = Console.ReadLine();
                if (input.Trim().ToLower() == "stop")
                {
                    Console.WriteLine("线程已停止运行...");
                    objMRE.Reset();
                }
                else if (input.Trim().ToLower() == "run")
                {
                    Console.WriteLine("线程开启运行...");
                    objMRE.Set();
                }
            }

        }

    }

在这里插入图片描述

信号同步的原理就是等待信号,有信号状态直接过,无信号就等。怎么等?通过调用WaitOnce等。Set设置信号为有信号,ReSet设置状态为无信号。AutoResetEvent就是等完之后会自动变成无信号!与之相反是ManualResetEven。

Manual翻译过来就是手动。需要显式调用 Reset 方法将其重置为无信号状态。

Semaphore sema = new Semaphore(x,y)
有一队人排队上洗手间,人就相当于线程,x为还剩余的位置数量,y为总的位置数量。
WaitOne()方法就相当于人在等待洗手间位置的行为,而Release()方法就相当于一个人从洗手间出来的行为,这里再假设x和y都为5,说明
开始的时候洗手间有5个空位置,且总共只有5个位置,当一队超过5个人的队伍要上洗手间的就排队,首先WaitOne()方法等待,发现有空
位就依次进去,每进去一个空位减一,直到进去5之后个没有空位,这时候后面的人就一直等待,直到进去的人从洗手间出来Release()方
法,空位加一,在等待WaitOne()方法的人发现有空位又进去一个空位减一……如此循环往复。
这里我要说明一点,信号量控制的只是线程同步的量,而不管顺序,这个例子来说线程控制的就是线程同步量为5,也就是同时并发的线程数量为5个,至于是哪个先哪个后不是由这里的信号量决定的。

public class Program
 {
	 static Semaphore sema = new Semaphore(5, 5);
	 const int cycleNum = 9;
	 static void Main(string[] args) 
	 {
		 for(int i = 0; i < cycleNum; i++)
		 {
			 Thread td = new Thread(new ParameterizedThreadStart(testFun));
			 td.Name = string.Format("编号{0}",i.ToString());
			 td.Start(td.Name);
		 }
		 Console.ReadKey();
 	}
	 public static void testFun(object obj)
	 {
		 sema.WaitOne();
		 Console.WriteLine(obj.ToString() + "进洗手间:" + DateTime.Now.ToString());
		 Thread.Sleep(2000);
		 Console.WriteLine(obj.ToString() + "出洗手间:" + DateTime.Now.ToString());
		 sema.Release();
 }
 }
 

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值