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,但由于多线程的关系,可能进入运算的时候,已经超过边界了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值