C#多线程开发-线程间通讯

前言

在实际的开发过程中,经常需要使用很多子线程来实现某些功能需求,有时候当主线程分配的任务过多或做一些需要长时间等待和响应的工作时单独使用子线程来实现可能更好,可是当我们程序中的子线程太多的时候,有些需求就需要在线程之间进行通讯或者传递消息。那么对于C#来说,是如何实现线程间通讯的。

一、AutoResetEvent

介绍

AutoResetEvent表示信号量,可用于线程间发送信号互相通讯,线程通过调用WaitOne来等待信号。

如果AutoResetEvent为非终止状态,则线程会被阻止,并等待当前控制资源的线程(主线程)调用Set()发出资源可用的信号时释放等待线程。此时AutoResetEvent将保持终止状态,直到一个正在等待的线程被释放,然后自动返回非终止状态。如果没有任何线程在等待,则状态将无限期保持为终止状态。

AutoResetEvent可在声明时,传递布尔值到构造函数,初始化其初始状态。若初始状态为终止状态则为true,否则为false。

简单解释就是非终止状态下子线程在使用AutoResetEvent在方法WainOne时需要等待AutoResetEvent的信号,否则不往下继续执行,无信号则一直等待。终止状态就是无需等待直接可以顺序执行。

//初始化为非终止状态
private AutoResetEvent threadOne = new AutoResetEvent(false);

常用方法

Set(): 表示AutoResetEvent发送信号,在主线程或者掌握资源的线程中使用。

WaitOne(): 等待信号,在子线程中使用,如果初始化的AutoResetEvent默认为非终止状态,当子线程运行到WaitOne()程序时,则线程等待,后面的不执行。直到Set()信号发出,才顺序执行。

Demo案例

假设我去书店买书,选中书后需要先去缴费处付钱,付完钱后去仓库取书,走就行。

在此业务中我属于主线程,收费处和仓库为子线程。

主线程

const int num = 400;
        //默认为非终止状态,必须得等待信号量。
         static AutoResetEvent threadPayMoneyOne = new AutoResetEvent(false);               
         static AutoResetEvent threadGetBookTwo = new AutoResetEvent(false);

        static int number;                           
        static void Main(string[] args)
        {
            Thread PaymoneyThread = new Thread(new ThreadStart(PayMoneyOne));
            PaymoneyThread.Name = "缴费线程";
            PaymoneyThread.Start();

            Thread GetBookThread = new Thread(new ThreadStart(GetBookTwo));
            GetBookThread.Name = "仓库线程";            
            GetBookThread.Start();

            for (int i = 0; i < num; i++)
            {
                Console.WriteLine("买书主线程:数量 "+i);
                number = i;

                //主线程通知两个子线程
                threadPayMoneyOne.Set();
                threadGetBookTwo.Set();
                Thread.Sleep(0);
            }

            PaymoneyThread.Abort();
            GetBookThread.Abort();
            
            Console.ReadKey();
        }

子线程

/// <summary>
        /// 缴费处
        /// </summary>
        static void PayMoneyOne() 
        {
            while (true)
            {
                threadPayMoneyOne.WaitOne();

                Console.WriteLine("Thread Name=" + Thread.CurrentThread.Name + ",number:" + number);
                Thread.Sleep(0);
            }
        }

        /// <summary>
        /// 仓库处
        /// </summary>
        static void GetBookTwo() 
        {
            while (true)
            {
                threadGetBookTwo.WaitOne();

                Console.WriteLine("Thread Name="+Thread.CurrentThread.Name+",number:"+number);
                Thread.Sleep(0);
            }
        }

验证图片

cf3b806fc7ae8a3cb3e9910ee1ea4b9c.png

可以发现当在主线程中循环的调用两个子线程的Set()方法后,子线程就会立即执行,否则就等待不往下执行。

利用AutoResetEvent中的Set()和WaitOne()来进行线程间的通讯,在日常的软件开发中可以帮助我们更好的实现更加复杂的业务。

二、ManualResetEvent

ManualResetEvent和AutoResetEvent都可用作线程间通讯的,字面意思看看到ManualResetEvent是手动通讯,AutoResetEvent是自动的。

两者用法基本一样,最最根本的不同是,AutoResetEvent在子线程中调用完WaitOne()方法后,AutoResetEvent就又进入到了非终止状态,其它调用了WaitOne的线程则必须继续等待。而ManualResetEvent则不同,它在调用完WWaitOne后不更改ManualResetEvent信号量的状态,其余调用WainOne的线程也可以收到信号。

若要使得ManualResetEvent和AutoResetEvent保持一致的行为,则在ManualResetEvent调用完WainOne后,再次调用Reset就可更改信号量状态。

技术群: 需要进技术群学习交流的请添加小编微信,切记备注:加群,对以上内容有什么疑问也可以直接和小编直接沟通交流!     

小编微信:mm1552923   

公众号:dotNet编程大全   

  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值