前几天一朋友问我如何实现线程的顺序执行,说真的,虽然看过CLR这本书,也把线程部分拜读了两遍,但是这个问题出来之后还是没有一个思路。今天在搜索资料的时候无意中再次看到AutoResetEvent这个东西,当然我知道它是和线程有关,用于处理线程切换之类的(可能在测试Demo之前理解有误),于是决定用AutoResetEvent来处理上面的问题。

这里以园区一个园友的例子来说明,这个例子就是 买书--》付款--》拿书这个过程,该过程会持续n(通过变量设置)次,并且每一次都要按照顺序执行,有可能有同学会疑问,直接Sleep不就好了,干嘛非要多个线程,如果处理某一个环节的时间过久或者是业务复杂,那么整个程序就直接未响应了,所以这里加入多线程来保证程序的响应。

class Program
{
//循环次数
const int numIterations = 10;
//买书
static AutoResetEvent buyResetEvent = new AutoResetEvent(false);
//付款
static AutoResetEvent payResetEvent = new AutoResetEvent(false);
//取书
static AutoResetEvent getBookEvent = new AutoResetEvent(false);
//循环的次数
static int number;
static void Main(string[] args)
{
//付款线程
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;
//允许付款线程等待
payResetEvent.Set();
//禁止买书线程等待
buyResetEvent.WaitOne();
}
Console.Read();
} static void PayMoneyProc()
{
while (true)
{
//等待付款
payResetEvent.WaitOne();
Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);
//允许取书线程等待
getBookEvent.Set();
}
}
static void GetBookProc()
{
while (true)
{
//等待付款
getBookEvent.WaitOne();
Console.WriteLine("{0}:数量{1}", Thread.CurrentThread.Name, number);
Console.WriteLine("------------------------------------------");
//允许买书线程等待(到这一步一个完整的买书流程就执行结束了,完全按照买书--》付款--》取书的流程)
buyResetEvent.Set();
}
}
}

上述代码不复杂,但是有几个关键的对象和方法,接下来详细进行说明。

1.分别定义了买书、付款、拿书三个AutoResetEvent,注意定义的时候传入了false,这也AutoSet默认是不可用的,需要手动调用Set方法才可以呢。该对象是决定是否能WaitOne一个请求的关键,当AutoResetEvent.Set执行则可以使用AutoResetEvent.WaitOne进行一个等待请求,如果再有WaitOne请求,则要继续等待Set的执行;

2.先看for循环,在循环中我们使用payResetEvent.Set()这句代码,这也PayThread中的WaitOne请求就可以获得批准(下文有介绍),同时我们又加上了buyResetEvent.WaitOne()(这样在上一次购买流程结束之前,新的一次流程是不可以执行的,这也就是我们的最大问题,保证线程按照顺序执行);

3.定义了付款和拿书的Thread,并且在方法内都是While循环,该循环主要是为了可以将我们的过程进行多次,毕竟线程只会执行一遍嘛。当然这个不是重点,重点是While中我们的操作,先看PayThrea的操作,先调用payResetEvent.WaitOne()请求一个等待操作,当然可以立马执行,因为在 2 中我们说了for中是调用了payResetEvent.Set()操作,这样就可以直接得到一个请求响应,输出关键信息,然后又到了重点,我们调用了getBookEvent.Set(),这是为什么呢,因为付款不成功是不可以拿书走的啊,那样就是偷盗了。注意、注意、注意,重要的话说三遍,GetBookThread操作中也有一个waitOne请求,可是为什么不会执行呢,因为没有Set呢,我们初始化AutoResetEvent的时候我们设置的是false,这样默认就不可以得到一个请求,必须手动调用Set才可以,由于在PayMoneyThread的最后一行代码中我们调用了getBookEvent.Set(),这样getBookEvent.WaitOne就可用了。在GetBookThread中依次输出关键信息,最后一行代码又来了,再次调用了一个AutoResetEvent.Set(),没错就是买书的对象,因为到了这一步完整的买书流程就结束了,可以再次买书了啊啊啊啊啊啊,可以买书了,好开心啊。然后再次回到for循环中的最后一行代码,buyResetEvent.Wait()此时就复活了,开始第好几次的买书流程。

运行截图如下(绝对真实,毫无PS):

好了,退朝,有事改天上朝再议。

Update:鉴于大家对这个使用方式有不同的建议,另外.net的版本都4.6了,所以重新使用Task的方式进行了更新,欢迎继续拍砖.

 static void Main(string[] args)
{
for (int i = ; i < ; i++)
{
Task buyTask = Task.Factory.StartNew(() =>
{
BuyBook();
}).ContinueWith((state) =>
{
PayMoney();
}).ContinueWith((state) =>
{
TakeBook();
});
Task.WaitAll(buyTask);
Console.WriteLine();
} Console.Read();
} private static void BuyBook()
{
Console.WriteLine("书太多了,挑花眼了");
} private static void PayMoney()
{
Console.WriteLine("先付钱才能取书哦");
} private static void TakeBook()
{
Console.WriteLine("取书喽");
}

C#之使用AutoResetEvent实现线程的顺序执行的更多相关文章

  1. Qt 控制线程的顺序执行(使用QWaitCondition,并且线程类的run函数里记得加exec(),使得线程常驻)

    背景项目中用到多线程,对线程的执行顺序有要求: A.一个线程先收数据 B.一个线程处理数据 C.一个线程再将处理后的数据发送出去 要求三个线程按照ABC的顺序循环执行. 思路子类化多线程方法 重写子类 ...

  2. 【Java并发】线程的顺序执行

    /** * 问题:有线程a.b.c,如何让它们顺序执行? * 方式一:可用Join()方法实现 * 方式二:可用newSingleThreadExecutor() * Created by Smile ...

  3. 三个线程abc顺序执行

    1.使用synchronized悲观锁(秋招阿里的一个笔试题,应该写的比较复杂,然后就没有然后了o(╥﹏╥)o) public class ThreadThreadp { private int fl ...

  4. java 多线程 实现多个线程的顺序执行

    场景 编写一个程序,启动三个线程,三个线程的name分别是A,B,C:,每个线程将自己的ID值在屏幕上打印5遍,打印顺序是ABCABC... 使用 synchronized 实现 public cla ...

  5. 用三个线程按顺序循环打印ABC三个字母

    有两种方法:semaphore信号量和mutex互斥锁.需要注意的是C++11已经没有semaphore. C++ 并发编程(六):信号量(Semaphore) - 止于至善 - SegmentFau ...

  6. Java中如何保证线程顺序执行

    只要了解过多线程,我们就知道线程开始的顺序跟执行的顺序是不一样的.如果只是创建三个线程然后执行,最后的执行顺序是不可预期的.这是因为在创建完线程之后,线程执行的开始时间取决于CPU何时分配时间片,线程 ...

  7. [Thread] 多线程顺序执行

    Join 主线程join 启动线程t1,随后调用join,main线程需要等t1线程执行完毕后继续执行. public class MainJoin { static class MyThread i ...

  8. AutoResetEvent信号锁 waitone set 执行一次线程退出 挺不爽的地方

    下边有个 循环调用线程写奇偶数的程序 class TheadTest { //定义一个Stream对象接收打开文件 private FileStream st; //构造方法 public Thead ...

  9. C# 使用AutoResetEvent进行线程同步

    AutoResetEvent 允许线程通过发信号互相通信. 通常,当线程需要独占访问资源时使用该类. 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号. 如果 AutoRe ...

随机推荐

  1. 使用xilinx ip core FIFO First- World First-Through (FWFT)模式的注意事项

    也许很多人知道xilinx ip core 中的fifo可以配成standard 模式和FWFT模式,并知道两者的区别是:standard模式下,当rd为高时,fifo会延时一个时钟输出数据(时序逻辑 ...

  2. Linux安装JBOSS

    一.简介 JBoss是一个运行EJB的J2EE应用服务器.它是开放源代码的项目,遵循最新的J2EE规范.从JBoss项目开始至今,它已经从一个EJB容器发展成为一个基于的J2EE的一个web 操作系统 ...

  3. 关于arguments对象以及函数的柯里化;

    1.arguments对象 Arguments是个类似数组但不是数组的对象,说他类似数组是因为其具备数组相同的访问性质及方式,能够由arguments[n]来访问对应的单个参数的值,并拥有数组长度属性 ...

  4. Java应用的优秀管理工具Maven的下载安装及配置

    1.进入Maven的官方下载地址:http://maven.apache.org/download.cgi 2.向下滚动页面,点击这个zip包进行下载: 3.将压缩包解压后剪切到Mac的某个目录下就完 ...

  5. 6、android 普通日志输出到SD卡

    这是本人见过写博文最负责的一个人: http://www.crifan.com/android_try_use_android_logging_log4j_to_output_log_to_sd_ca ...

  6. 【Path Sum】cpp

    题目: Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up ...

  7. ASP.NET本质论阅读----线程与异步

    线程 概要:操作系统通过线程对程序的执行进行管理 线程的数据结构:1.线程的核心对象(包含线程的当前寄存器状态),调用线程时-寄存器状态被加载到CPU中. 2.线程环境块TEB:一块用户模式下的内存 ...

  8. hdu 4193 Non-negative Partial Sums

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4193 题意:给出一个n数列,要求把前i(1<=i<=n)个数移到剩余数列的后面形成新的数列 ...

  9. opencv中的Bayes分类器应用实例

    转载:http://blog.csdn.net/yang_xian521/article/details/6967515 PS:很多时候,我们并不需要特别精通某个理论,而且有的时候即便你非常精通,但是 ...

  10. Codeforces Round #283 (Div. 2)

    A:暴力弄就好,怎么方便怎么来. B:我们知道最多加10次, 然后每次加1后我们求能移动的最小值,大概O(N)的效率. #include<bits/stdc++.h> using name ...