概述
要想两个线程轮流打印,最常见的办法是加一个锁,每当该线程获取到锁后就打印,然后释放锁,让另一个线程打印,但锁也有它的局限性,比如,如果有四个线程,两两轮流使用,可能就需要2个锁,这不是一个好办法,这里介绍一个C#内置的工具:Semaphore,即信号量的意思。是操作系统原始提供的内核同步对象。
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 收到信号。
所以有了上面的介绍,我们就知道怎么去控制两个线程轮流打印了:每次只允许一个线程进入。
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 -----T1
2 -----T2
3 -----T1
4 -----T2
5 -----T1
6 -----T2
当然嫌麻烦可以两两个奇偶打印函数卸载一起:
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# 两个线程轮流打印所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复