AutoResetEvent详解(线程独占访问资源)

由来:

在学习工作流的过程中,宿主程序中会出现这么一段代码:

staticAutoResetEvent instanceUnloaded = new AutoResetEvent(false);

然后就是在方法中这样使用:

instanceUnloaded.Set();//将事件状态设置为终止状态,允许一个或多个等待线程继续

instanceUnloaded.WaitOne();//对于WaitOne方法为阻止当前线程,直到收到信号!

对于这部分内容当时不是很理解,下面我们先介绍一下AutoResetEvent的作用,然后结合工作流分析这些代码的意图!

举个例子:

我去书店买书,当我选中一本书后我会去收费处付钱,付好钱后再去仓库取书。这个顺序不能颠倒,我作为主线程,付钱和取书做两个辅助线程

代码如下:

using System;
using System.Linq;
using System.Activities;
using System.Activities.Statements;
using System.Threading;
 
namespace CaryAREDemo
{
    class Me
    {
        const int numIterations = 550;
        static AutoResetEvent myResetEvent = new AutoResetEvent(false);
        static AutoResetEvent ChangeEvent = new AutoResetEvent(false);
        static int number; //这是关键资源
 
	//主线程
        static void Main()
        {
            Thread payMoneyThread = new Thread(new ThreadStart(PayMoneyProc));
            payMoneyThread.Name = "付钱线程";
            Thread getBookThread = new Thread(new ThreadStart(GetBookProc));
            getBookThread.Name = "取书线程";
	    //启动线程
            payMoneyThread.Start();
            getBookThread.Start();
 
            for (int i = 1; i <= numIterations; i++)
            {
                Console.WriteLine("买书线程:数量{0}", i);
                number = i;
                //Signal that a value has been written.
                //允许线程继续
                myResetEvent.Set();
                ChangeEvent.Set();
                Thread.Sleep(0);
            }
            payMoneyThread.Abort();
            getBookThread.Abort();
        }
 
        static void PayMoneyProc()
        {
            while (true)
            {
	        //等待满足条件
                myResetEvent.WaitOne();
                Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);
            }
        }
        static void GetBookProc()
        {
            while (true)
            {
		//等待满足条件
                ChangeEvent.WaitOne();                            
                Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);
                Console.WriteLine("------------------------------------------");
                Thread.Sleep(0);
            }
        }
    }
}

运行结果:

说明:

AutoResetEvent允许线程通过发信号互相通信。通常,此通信涉及线程需要独占访问的资源。

1,通过将一个布尔值传递给构造函数来控制AutoResetEvent的初始状态,如果初始状态为终止状态,则为 true即该线程阻塞,并等待当前控制资源的线程;否则为 false。

2,线程也可以通过调用AutoResetEvent 上的 WaitOne 来等待信号。

3,通过调用 Set发出资源可用的信号,以释放等待线程。

通俗的来讲只有等myResetEven.Set()成功运行后,myResetEven.WaitOne()才能够获得运行机会;Set是发信号,WaitOne是等待信号,只有发了信号,等待的才会执行。如果不发的话,WaitOne后面的程序就永远不会执行。

结合工作流的宿主程序:

创建工作流:

static AutoResetEvent instanceUnloaded = new AutoResetEvent(false);
 public static Guid CreateAndRun(RequestInfo.RequestInfo Request)
        {
            SqlWorkflowInstanceStore instanceStore = new SqlWorkflowInstanceStore("server=.;database=aspnetdb;uid=sa;pwd=123456");

            InstanceView view = instanceStore.Execute(instanceStore.CreateInstanceHandle(), new CreateWorkflowOwnerCommand(), TimeSpan.FromSeconds(30));

            instanceStore.DefaultInstanceOwner = view.InstanceOwner;

            IDictionary<string, object> input = new Dictionary<string, object>
            {
                { "Request" , Request }
            };

            WorkflowApplication application = new WorkflowApplication(new ApplyBlogFlow(), input);

            application.InstanceStore = instanceStore;

            //获取或设置当前工作流实例处于空闲状态并可被保留时调用的 ActivityFunc
            application.PersistableIdle = (e) =>
            {
                instanceUnloaded.Set();
                return PersistableIdleAction.Unload;

            };
            //获取或设置卸载当前工作流
            application.Unloaded = (e) =>
            {

                instanceUnloaded.Set();

            };
            //获取或设置当前工作流实例遇到未处理的异常时
            application.OnUnhandledException = (ex) =>
            {
                Console.Write("Exception");
                return UnhandledExceptionAction.Terminate;
            };

            Guid id = application.Id;

            application.Run();
            //阻止当前线程,直到当前waithand收到信号
            instanceUnloaded.WaitOne();

            return id;

        }

仔细看这段代码,在初始时将AutoResetEvent(false),即非终止状态,但是当application.Run();之后就WaitOne,说明此时将AutoResetEvent设置成了终止状态,即阻塞当前线程。为什么要这样呢?目的很简单,因为这个执行过程为异步,如果当调用启动工作流的方法后,不去阻止当前方法的执行,那么这个方法就这样执行结果,返回我们创建成功,可是问题就是,这个时候很可能工作流还没有执行完成,而结果却先告诉我们了,这样显然不合理。

如果大家对于上述的解释还不理解,可以参考下调用流程:

CreateAndRun开始---》WaitOne---》当前线程被阻止,即不再往下执行---》真正启动工作流---》工作流执行完等待流后会被设置为空闲状态---》PersistableIdle---》instanceUnloaded.Set();---》AutoResetEvent可以继续---》
return id;---》整个方法执行完成

总结:

用AutoResetEvent实现同步,只是众多方法中之一,记得当时在考试系统的教师判分处应用了锁,当时使用的是数据库锁,保证某个表同一时间只能有一个用户在操作,这也是一个实现同步的方式,而且我们在学习java时也知道synchronized实现方法同步等方式。无论是数据库锁,synchronized,还是AutoResetEvent的方式只是它们的侧重不同,针对的对象不同,但是目的都是在控制操作的同步进行。

其实对于多线程的同步问题就是在程序的执行时多了一步验证(一个门一次只能通过一个即n=1的情况),是可以执行,还是需要等待而已,对于不同的同步技术只是对不同的对象设置验证,如数据库锁是对表的操作进行限制。

通过整理发现,其实AutoResetEvent只是实现同步的一种方式,并没有当时想的那么深奥,关键还是在于对于不懂的知识的学习与整理,了解到它是解决同步的方式后,再结合我们之前使用过的一些同步方法,这些知识就又简单了,所以我们面对学也就开心了!

时间: 2024-08-02 02:23:35

AutoResetEvent详解(线程独占访问资源)的相关文章

干货分享:详解线程的开始和创建

阅读目录 代码下载 一.线程的创建和开始 二.传递数据给一个线程 三.命名线程 四.前台线程和后台线程 五.线程优先级 六.异常处理 原文地址:C#多线程之旅(2)--创建和开始线程 C#多线程之旅目录: C#多线程之旅(1)--介绍和基本概念 C#多线程之旅(2)--创建和开始线程 C#多线程之旅(3)--线程池 C#多线程之旅(4)--APM初探 C#多线程之旅(5)--同步机制介绍 C#多线程之旅(6)--详解多线程中的锁 更多文章正在更新中,敬请期待...... C#多线程之旅(2)--

AQS详解之独占锁模式

AQS介绍 AbstractQueuedSynchronizer简称AQS,即队列同步器.它是JUC包下面的核心组件,它的主要使用方式是继承,子类通过继承AQS,并实现它的抽象方法来管理同步状态,它分为独占锁和共享锁.很多同步组件都是基于它来实现的,比如我门常见的ReentrantLock,它是基于AQS的独占锁实现的,它表示每次只能有一个线程持有锁.在比如ReentrantReadWriteLock它是基于AQS的共享锁实现的,它允许多个线程同时获取锁,并发的访问资源.AQS是建立在CAS上的

AutoResetEvent详解

在MSDN中,它的解释为:通知正在等待的线程已发生事件.无法继承此类(密封类). AutoResetEvent 允许线程通过发信号进行相互通信,例如发Set信号,让正在WaitOne等待信号着的线程开启继续执行.通常,此通信涉及线程需要独立访问的资源. 线程通过调用 AutoResetEvent 上的WaitOne来等待信号.如果 AutoResetEvent 处于非终止状态,则该线程阻塞,并等待当前控制资源的线程通过调用 Set发出资源可用的信号. 调用 Set 向 AutoResetEven

详解线程的信号量和互斥锁

前言:有个问题感觉一直会被问道:进程和线程的区别?也许之前我会回答: 进程:资源分配最小单位 线程:轻量级的进程 是系统调度的最小单位 由进程创建 多个线程共享进程的资源 但是现在我觉得一个比喻回答的更好:程序就像静止的火车,进程是运行的火车,线程是运行火车的每节车厢. 个人感觉理解远比背些概念性东西更好. 一.线程 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义.线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而

详解JNDI的lookup资源引用 java:/comp/env

ENC的概念: The application component environment is referred to as the ENC, the enterprise naming context. 应用组件的业务逻辑应该是 ENC中取得对象.组件提供者使用标准的部署描述符指定必需的ENC入口.这些ENC入口是运行时组件所依赖的资源等信息. 一个应用组件实例使用 JNDI定位ENC.ENC的标准JNDI CONTEXT是:java;/comp/env // Obtain the appl

并发编程 — 详解线程池

本文将讲述如何通过JDK提供的API自定义定制的线程池 Java代码   //固定线程数 -- FixedThreadPool public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } //单

并发编程学习总结(二) : 详解 线程的6种不同状态

(一) 线程状态: 我们先讨论一下线程的几种状态: java中Thrad.State总共有6中状态: (1)New (新创建) (2)Runnable (可运行) (3)Bolcked (被阻塞) (4)Waiting (等待) (5)Timed Waiting (计时等待) (6)Terminated (被终止) 这里先列出各个线程状态发生的条件,下面将会对每种状态进行详细解析和代码实例. 下面我们分别看一下线程的这6中状态分别出现在什么情况下. (1)New (新创建) 当我们执行new T

java线程详解

Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. “同时”执行是人的感觉,在线程之间实际上轮换执行. 二.Jav

Java线程详解----借鉴

Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. “同时”执行是人的感觉,在线程之间实际上轮换执行. 二.Jav