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

概述

要想两个线程轮流打印,最常见的办法是加一个锁,每当该线程获取到锁后就打印,然后释放锁,让另一个线程打印,但锁也有它的局限性,比如,如果有四个线程,两两轮流使用,可能就需要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# 两个线程轮流打印所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部