ManualResetEvent用法「建议收藏」

ManualResetEvent用法「建议收藏」ManualResetEvent用法

大家好,又见面了,我是你们的朋友全栈君。

                 
http://blog.tom.com/blog/read.php?bloggerid=313638&blogid=13505


Thread and Sync In C# (C#中的线程与同步)

别相信别人告诉你的所有的事。其实C#中的线程是很简单的。

线程是程序中的控制流程的封装。你可能已经习惯于写单线程程序,也就是,程序在它们的代码中一次只在一条路中执行。如果你多弄几个线程的话,代码运行可能会更加“同步”。在一个有着多线程的典型进程中,零个或更多线程在同时运行。但是,在有着N个CPU的机器上,一个线程只能在给定的时间上在一个CPU上运行,因为每个线程都是一个代码段,每个CPU一次只能运行一段代码。而看起来像是N个同时完成是线程间共享CPU时间片的效果。这个例子里,我们将创建另一个线程,我们将用两个线程演示多线程的工作方式,最后,我们实现两个线程(主线程与新线程)同步,在新线程工作前必须等待消息。建立线程前我们必须引入System.Threading命名空间。然后我需要知道的是,线程得为控制流程建立一个起点。起点是一个函数,可以使一个相同的调用或其它。

这里你可以看到在同一个类中定义的起点函数。

None.gif using  System;

None.gif using  System.Threading;

None.gif namespace  ThreadingTester

ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif
{

InBlock.gifclass ThreadClass
ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{

InBlock.gif  public static void trmain()
ExpandedSubBlockStart.gifContractedSubBlock.gif  dot.gif{

InBlock.gif    for(int x=0;x < 10;x++)
ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{

InBlock.gif    Thread.Sleep(1000);
InBlock.gif    Console.WriteLine(x);
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif  }
  
InBlock.gif  static void Main(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif  dot.gif{

InBlock.gif    Thread thrd1=new Thread(new ThreadStart(trmain));
InBlock.gif    thrd1.Start();
InBlock.gif    for(int x=0;x < 10;x++) 
ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{

InBlock.gif    Thread.Sleep(900);
InBlock.gif    Console.WriteLine(“Main    :” + x);
ExpandedSubBlockEnd.gif    }

ExpandedSubBlockEnd.gif  }

ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}


None.gif

Thread.Sleep(n)方法把“this”线程置于n毫秒的休眠状态。你可以看看这个例子,在主函数我们定义了一个新的线程,其中它的起点是函数trmain(),我们然后包含了Start()方法开始执行。如果你运行这个例子,你就会了解线程间的切换(让CPU从运行一个线程转到另一个线程)让线程几乎同时运行,为了能看哪个线程运行更快我把主线程设置比新线程少100毫秒。

现在,在开始线程前,先给线程命名:

  Thread thrd1=new Thread(new ThreadStart(trmain));

  thrd1.Name=”thread1″;

  thrd1.Start();

  Thread tr = Thread.CurrentThread;

  Console.WriteLine(tr.Name);

在完成上面程序后,设想我们不想在一开始新线程就让它马上运行结束,也就是说,我们开启了一个新线程,让它运行,在某个特定的时间点,新线程暂停并等待从主线程(或其他线程)发来的消息。

我们可以这样定义:

  public static ManualResetEvent mre = new ManualResetEvent(false);

ManualResetEvent建立时是把false作为start的初始状态,这个类用于通知另一个线程,让它等待一个或多个线程。注意,为了通知或监听同一个线程,所有的其它线程都能访问那个类。

等待线程这样写:

  mre.WaitOne();

这将引起等待线程无限期的阻塞并等待类来通知。

发信号的线程应该这样:

  mre.Set();

这样类就会被通知,值变成true,等待线程就会停止等待。在通知事件发生后,我们就可以使用下面语句把线程置于基状态:

  mre.Reset();

现在让我们在程序执行一下:

None.gif using  System;

None.gif using  System.Threading;

None.gif namespace  ThreadingTester

ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif
{

InBlock.gifclass ThreadClass
ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{

InBlock.gifpublic static ManualResetEvent mre=new ManualResetEvent(false);
InBlock.gifpublic static void trmain()
ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{

InBlock.gifThread tr = Thread.CurrentThread;
InBlock.gifConsole.WriteLine(“thread: waiting for an event”);
InBlock.gifmre.WaitOne();
InBlock.gifConsole.WriteLine(“thread: got an event”);
InBlock.giffor(int x=0;x < 10;x++)
ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{

InBlock.gifThread.Sleep(1000);
InBlock.gifConsole.WriteLine(tr.Name +”: ” + x);
ExpandedSubBlockEnd.gif}

ExpandedSubBlockEnd.gif}
  
InBlock.gifstatic void Main(string[] args)
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{

InBlock.gifThread thrd1=new Thread(new ThreadStart(trmain));
InBlock.gifthrd1.Name=”thread1″;
InBlock.gifthrd1.Start();
InBlock.giffor(int x=0;x < 10;x++) 
ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{

InBlock.gifThread.Sleep(900);
InBlock.gifConsole.WriteLine(“Main:” + x);
InBlock.gifif(5==x) mre.Set();
ExpandedSubBlockEnd.gif}

InBlock.gifwhile(thrd1.IsAlive)
ExpandedSubBlockStart.gifContractedSubBlock.gifdot.gif{

InBlock.gifThread.Sleep(1000);
InBlock.gifConsole.WriteLine(“Main: waiting for thread to stopdot.gif“);
ExpandedSubBlockEnd.gif}

ExpandedSubBlockEnd.gif}

ExpandedSubBlockEnd.gif}

ExpandedBlockEnd.gif}

 

两者都继承自EventWaitHandle,自然也就有点相通的地方了

 

简单来说,无论是AutoResetEvent还是ManualResetEvent,都是通过发出Signal信号来通知正在等待的线程的。有人可能要问,为什么要用它们来做这些事情, 嗯, 是这样的, 在.Net的多线程环境中,资源的共享变得尤其重要,如果没有一个有效的方法来维护资源的原子状态,在抢占式的CPU环境中,所有的事情都会变得无法控制。AutoResetEvent和ManualResetEvent正是用来保证资源的原子性的一个手段的两个方面。正如它们的名字一样, AutoResetEvent会在每次被Signal了之后自动(Automatically)转变为UnSignal,而ManualResetEvent则不然,无论是Signal还是UnSignal都需要人为的介入去改变它的状态。

 

在AutoResetEvent的构造函数中,有唯一的一个参数,initialState,Boolean类型,它用来初始化AutoResetEvent的Signal状态,True为Signal,False为UnSignal,这与ManualResetEvent的构造函数是一样的。

 

AutoResetEvent或ManualResetEvent都是通过Set()/Reset()两个方法来Signal/UnSignal信号,通过调用WaitOne方法来阻塞当前线程,当收到Signal后就继续往下执行。上面提到过,AutoResetEvent会自动把信号复位(自动调用Reset),而ManualResetEvent则需要人手复位,也就是说,AutoResetEvent每次只允许一条线程进入,其它所有需要访问该资源的线程都要排队等候,直到AutoResetEvent得到信号后,下一条线程开始工作,同时AutoResetEvent又会自动复位信号,让其他线程继续等候;而ManualResetEvent则每次可以唤醒多个线程,因为当ManualResetEvent得到信号后,其他调用WaitOne方法的线程都将得到信号得以继续往下执行,ManualResetEvent不会自动复位信号,换句话说,除非手动的调用了ManualResetEvent.Reset方法,否则ManualResetEvent一直保持有信号状态,这样就可以同时唤醒多条线程了

 

作为一个示例,下面的DemoCode一开始就运行一条子线程,然后用AutoResetEvent/ManualResetEvent来控制MessageBox的输出流程。

如果在Foo和button1_Click里面用AutoResetEvent,一开始得到”1″,然后每点击一次Button1得到”2″和”3″。

如果用ManualResetEvent,一开始得到”1″,然后只需点击Button1一次,就可以得到”2″和”3″了

 

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/158564.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 震荡波病毒原代码(勒索病毒源代码)

    #include#include#include#include#include#defineNORM”/033[00;00m”#defineGREEN”/033[01;32m”#defineYELL”/033[01;33m”#defineRED”/033[01;31m”#defineBANNERGREEN”[%%]”YELL”mandrag

    2022年4月14日
    79
  • Iocomp 5.12 SP6 ActiveX Crack

    Iocomp 5.12 SP6 ActiveX Crack不需要安装,免去大家下载,Q578867473安装需要注册账号的麻烦的IocompActiveX/VCL标准包是由29个控件组成的套件,Q578867473用于使用ActiveX或VCL开发环境创建专业的仪表应用程序。这些控件可用于科学,工程,医学,石油和天然气,半导体,工厂自动化,航空航天,军事,机器人技术,电信,楼宇和家庭自动化,HMI,SCADA以及数百种其他类型的应用程序。所有Iocomp控件均启用OPC。如果您的项目需要OPC连接,则可以将任何属性连接到OPC项/标签。所有连接都可

    2022年7月25日
    9
  • form表单提交的几种方式

    表单提交方式一:直接利用form表单提交html页面代码:<!DOCTYPEhtml><html><head><metacharset=”UTF-8″/><title>Inserttitlehere</title></head><body><formaction=”h…

    2022年4月1日
    56
  • Linux chmod命令用法

    Linux chmod命令用法chmod—-改变一个或多个文件的存取模式(mode) chmod[options]modefiles 只能文件属主或特权用户才能使用该功能来改变文件存取模式。mode可以是数字形式或以whoopcodepermission形式表示。who是可选的,默认是a(所有用户)。只能选择一个opcode(操作码)。可指定多个mode,以逗号分开。 options:

    2022年6月24日
    21
  • 简单图文解释冯诺依曼体系结构(通俗易懂版)

    简单图文解释冯诺依曼体系结构(通俗易懂版)冯诺依曼式计算机主要由输入设备,输出设备,控制器,运算器,存储器该五个组成部分构成。我们可以将该体系结构的运作通过人类接收信息,处理信息,并输出信息这个过程来加以类比理解。人类:当眼睛看到某些信息,这些信息被存储到记忆装置,大脑从记忆装置取出信息,并加以思考运算,再放回记忆装置,大脑控制记忆装置将信息传输给嘴巴,将信息表达出来。(这个过程大脑的指令占领导地位)冯诺依曼计算机:当输入设备接收到数据,数据将被存储到存储器,控制器发出取数据和运算的指令,数据被取出方去放入运算器中加以运算,运算结束后,控制器

    2025年6月11日
    5
  • 查询linux ssh端口,查看ssh端口「建议收藏」

    查询linux ssh端口,查看ssh端口「建议收藏」rpm-qa|grepssh可以看到系统中ssh安装包ps-ef|grepssh查看ssh服务有没有运行,如果有,可以看到类似以下内容:root26591018:31?00:00:00/usr/sbin/sshdroot27022618018:38pts/000:00:00grepssh这证明ssh已经在运行了,进程名为sshd如果没有运行,可以通过…

    2025年8月4日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号