我是靠谱客的博主 风中冬瓜,这篇文章主要介绍C# 两个线程轮流打印,现在分享给大家,希望可以做个参考。

要想两个线程轮流打印,最常见的办法是加一个锁,每当该线程获取到锁后就打印,然后释放锁,让另一个线程打印,但锁也有它的局限性,比如,如果有四个线程,两两轮流使用,可能就需要2个锁,这不是一个好办法,这里介绍一个C#内置的工具:Semaphore,即信号量的意思。是操作系统原始提供的内核同步对象。

复制代码
1
2
Semaphore semaphoreObject = new Semaphore(initialCount: 0, maximumCount: 5);

解释一下意思:

第一个参数为:initialCount ,意指初始数量。Semaphore这个对象的使用是这么回事:在initialCoun设置为0的时候,WaitOne()方法会直接阻塞。直到它的Release方法被调用位置。但是如果initialCount>0,那么一开始便不会阻塞WaitOne方法N次。

第二个参数为maximumCount,即最大并发数。

第三个参数的话,我刚说它是操作系统的内核对象,那么又是可以用作跨进程线程同步的。

可理解为允许线程执行信号的池子,池子中放入多少个信号就允许多少线程同时执行。

1、如果semaphore.Release(n),n>semaphore最大容纳信号量,将出异常。
2、当semaphore拥有的信号量为1时,Semaphore相当于Mutex
3、当semaphore拥有的信号量>1时,信号量的数量即可供多个线程同时获取的个数,此时可认为获取到信号量的线程将同时执行(实际情况可能与CPU核心数、CPU同时支出线程数有关)

Semaphore常用的方法有两个WaitOne()Release(),Release()的作用是退出信号量并返回前一个计数,而WaitOne()则是阻止当前线程,直到当前线程的WaitHandle 收到信号。

所以有了上面的介绍,我们就知道怎么去控制两个线程轮流打印了:每次只允许一个线程进入。

复制代码
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
62
63
64
65
66
67
68
69
static void Main(string[] args) { Printer printer = new Printer(); Thread thread1 = new Thread(printer.PrintOddAndEven) { Name = "T1" }; Thread thread2 = new Thread(printer.PrintOddAndEven) { Name = "T2" }; thread1.Start(); thread2.Start(); } class Printer { public int[] arr = new int[] { 1, 2, 3, 4, 5, 6 }; public int Index = 0; // private static Mutex mutex = new Mutex(); private static Semaphore semaphore = new Semaphore(1, 1); public void Print(int documentToPrint) { Console.WriteLine("Printing document: " + documentToPrint); //code to print document Thread.Sleep(TimeSpan.FromSeconds(5)); } public void PrintOdd() { while (Index < arr.Length) { // mutex.WaitOne(); semaphore.WaitOne(); if (Index % 2 == 1) { if (Index >= arr.Length) { // semaphore.Release(); return; } Console.WriteLine($"{arr[Index]} -----{Thread.CurrentThread.Name}"); Interlocked.Increment(ref Index); } semaphore.Release(); // mutex.ReleaseMutex(); } } public void PrintEven() { while (Index < arr.Length) { semaphore.WaitOne(); // mutex.WaitOne(); if (Index % 2 == 0) { if (Index >= arr.Length) { // semaphore.Release(); return; } Console.WriteLine($"{arr[Index]} -----{Thread.CurrentThread.Name}"); Interlocked.Increment(ref Index); } // mutex.ReleaseMutex(); semaphore.Release(); } } }

打印结果如下:

复制代码
1
2
3
4
5
6
1 -----T1 2 -----T2 3 -----T1 4 -----T2 5 -----T1 6 -----T2

当然嫌麻烦可以两两个奇偶打印函数卸载一起:

复制代码
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
public void PrintOddAndEven() { while (Index < arr.Length) { if (Index % 2 == 1) { semaphore.WaitOne(); if (Index >= arr.Length) { // semaphore.Release(); return; } Console.WriteLine($"{arr[Index]} -----{Thread.CurrentThread.Name}"); // Interlocked.Increment(ref Index); Index++; semaphore.Release(); } if (Index % 2 == 0) { semaphore.WaitOne(); if (Index >= arr.Length) { // semaphore.Release(); return; } Console.WriteLine($"{arr[Index]} -----{Thread.CurrentThread.Name}"); // Interlocked.Increment(ref Index); Index++; semaphore.Release(); } }

当然这里有个小问题就是,必须检查数组越界,虽然循环条件是小于arr.Length,但由于多线程的关系,可能进入运算的时候,已经超过边界了。

最后

以上就是风中冬瓜最近收集整理的关于C# 两个线程轮流打印的全部内容,更多相关C#内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(70)

评论列表共有 0 条评论

立即
投稿
返回
顶部