page contents

C#多线程之线程同步WaitHandle

本文讲述了c#多线程之线程同步WaitHandle!具有很好的参考价值,希望对大家有所帮助。一起跟随六星小编过来看看吧,具体如下:

attachments-2022-08-bhE28IHm62f30af3494a7.png本文讲述了c#多线程之线程同步WaitHandle!具有很好的参考价值,希望对大家有所帮助。一起跟随六星小编过来看看吧,具体如下:

在前面的文章中,我们是使用“锁”的方式实现了线程间的通信,这种通信方式比较笨重。除了锁之外,.NET中还提供了一些线程间更自由通讯的工具,他们提供了通过“信号”进行通讯的机制,通俗的比喻为“开门”、“关门”:Set()开门、Reset()关门、WaitOne()等着。

二、WaitHandle

WaitHandle位于System.Threading命名空间下,是用来封装等待对共享资源进行独占访问的操作系统特定的对象。WaitHandle是一个抽象类,我们一般不直接使用,而是使用它的派生类:

  • AutoResetEvent。
  • EventWaitHandle。
  • ManualResetEvent。
  • Mutex。
  • Semaphore。

1、AutoResetEvent

AutoResetEvent表示线程同步事件在一个等待线程释放后收到信号时自动重置。此类不能被继承。

是一个自动阻塞,WaitOne()方法阻塞程序执行,Set()方法释放信息。当释放后阻塞的代码继续执行。但下一次执行还需要等待信号。

通俗来说,WaitOne()是关门,Set()是开门。但开门之后,执行完又自动关门,还需要开门。可以知道超时时间:

1
2
// 设置超时时间为2秒,如果2秒后没有信号程序继续执行
are.WaitOne(2000);

看下面的一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System;
using System.Threading;
 
namespace AutoResetEventDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 通过构造函数创建,默认是关门
            AutoResetEvent are = new AutoResetEvent(false);
            Thread t1 = new Thread(() => {
                while (true)
                {
                    Console.WriteLine("开始等着开门");
                    // 执行完WaitOne之后自动关门
                    are.WaitOne();
                    Console.WriteLine("又关门了");
                }
            });
            // 启动线程
            t1.Start();
            Console.WriteLine("按任意键开门");
            Console.ReadKey();
            //开门
            are.Set();
 
            Console.WriteLine("按任意键开门");
            Console.ReadKey();
            //开门
            are.Set();
 
            Console.WriteLine("按任意键开门");
            Console.ReadKey();
            //开门
            are.Set();
 
            Console.ReadKey();
        }
    }
}

程序输出结果:

举一个形象点的例子,AutoResetEvent相当于火车或者地铁的闸机口,过了一个以后自动关门。

2、ManualResetEvent

Manual表示手动的。看下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
using System.Threading;
 
namespace ManualResetEventDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 通过构造函数初始化
            // false表示“初始状态为关门”,设置为true则表示初始状态为开门
            ManualResetEvent mre = new ManualResetEvent(false);
 
            // 创建一个线程
            Thread t1 = new Thread(() =>
            {
                // 因为初始化的状态为关门
                Console.WriteLine("开始等着开门");
                // 调用等着开门的方法,只有开门以后才会执行下面的代码
                mre.WaitOne();
                // 开门之后才会执行这句代码
                Console.WriteLine("终于开门了");
            });
 
            // 启动线程
            t1.Start();
 
            Console.WriteLine("按任意键开门");
            Console.ReadLine();
            // 调用开门的方法
            mre.Set();
 
            Console.ReadKey();
 
        }
    }
}

运行程序,什么也不输入,看一下输出结果:

我们随意输入,再看运行结果:

怎么关门呢?关门也需要我们手动的调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;
using System.Threading;
 
namespace ManualResetEventDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 通过构造函数初始化
            // false表示“初始状态为关门”,设置为true则表示初始状态为开门
            ManualResetEvent mre = new ManualResetEvent(false);
 
            // 创建一个线程
            Thread t1 = new Thread(() =>
            {
                // 因为初始化的状态为关门
                Console.WriteLine("开始等着开门");
                // 调用等着开门的方法,只有开门以后才会执行下面的代码
                mre.WaitOne();
                // 开门之后才会执行这句代码
                Console.WriteLine("终于开门了");
            });
 
            // 启动线程
            t1.Start();
 
            Console.WriteLine("按任意键开门");
            Console.ReadLine();
            // 调用开门的方法
            mre.Set();
            // 休眠3秒
            Thread.Sleep(3000);
            // 关门
            mre.Reset();
            Console.WriteLine("关门了");
 
            Console.ReadKey();
 
        }
    }
}

程序输出结果:

WaitOne()方法还可以设置等待超时时间,超过了等待时间就不会再等了。如果不设置等待超时时间,那么就会一直等下去。看下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using System;
using System.Threading;
 
namespace ManualResetEventDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 通过构造函数初始化
            // false表示“初始状态为关门”,设置为true则表示初始状态为开门
            ManualResetEvent mre = new ManualResetEvent(false);
 
            //// 创建一个线程
            //Thread t1 = new Thread(() =>
            //{
            //    // 因为初始化的状态为关门
            //    Console.WriteLine("开始等着开门");
            //    // 调用等着开门的方法,只有开门以后才会执行下面的代码
            //    mre.WaitOne();
            //    // 开门之后才会执行这句代码
            //    Console.WriteLine("终于开门了");
            //});
 
            // 创建一个线程
            Thread t1 = new Thread(() =>
            {
                // 因为初始化的状态为关门
                Console.WriteLine("开始等着开门");
                // 设置超时等待时间为5秒钟
                if(mre.WaitOne(5000))
                {
                    // 开门之后才会执行这句代码
                    Console.WriteLine("终于开门了");
                }
                else
                {
                    // 等待超时
                    Console.WriteLine("过了5秒钟了还没开门");
                }
                 
            });
 
            // 启动线程
            t1.Start();
 
            Console.WriteLine("按任意键开门");
            Console.ReadLine();
            // 调用开门的方法
            mre.Set();
            // 休眠3秒
            Thread.Sleep(3000);
            // 关门
            mre.Reset();
            Console.WriteLine("关门了");
 
            Console.ReadKey();
 
        }
    }
}

运行程序,什么也不输入,看运行结果:

WaitHandle.WaitAll(WaitHandle[] waitHandles)用来等待所有信号都变为“开门状态”,WaitHandle.WaitAny(WaitHandle[] waitHandles) 用来等待任意一个信号都变为“开门状态”。

ManualResetEvent是一旦设定Set()后就一直开门,除非调用Reset()方法关门。

举一个形象点的例子,ManualResetEvent就相当于是学校的大门,只要开门以后大家都可以进入,除非主动关门(等于执行了Reset()方法)。

到此这篇关于C#多线程之线程同步WaitHandle的文章就介绍到这了。更多相关技术内容咨询欢迎前往并持续关注六星社区了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2022-08-10 09:34
  • 阅读 ( 483 )
  • 分类:C/C++开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
轩辕小不懂
轩辕小不懂

2403 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1312 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章