使用双线程打印c中的偶数和奇数,即偶数线程和奇数线程

本文关键字:线程 打印 | 更新日期: 2023-09-27 18:23:57

/*我的要求是一个线程应该打印偶数,而另一个线程则应该打印奇数。这些线程应按顺序打印数字(1、2、3、4、5…)

我已经完成了这段代码,但当我对方法countThreadOdd.Start()或countThreadEvend.Start()进行注释时,它不会只打印偶数或奇数。*/

class Program
{
    static Object locker = new Object();
    static LinkedList<int> number = new LinkedList<int>();
    static int counter = 0;
    static void Main(string[] args)
    {
        Thread countThreadOdd = new Thread(oddThread);
        Thread countThreadEven = new Thread(evenThread);
        //Thread Start
        countThreadOdd.Start();
        countThreadEven.Start();
        //main thread will untill below thread is in exection mode
        countThreadOdd.Join(10);
        countThreadEven.Join(10);
        Console.ReadLine();
    }
    //Odd Thread
    public static void oddThread()
    {
        for (; counter < 10; )
        {
            //Lock the another thread to enter in critial area
            lock (locker)
            {
                if (counter % 2 != 0)
                {
                    Console.WriteLine(counter);
                    counter++;
                }
            }
        }
    }
    //Even Thread
    public static void evenThread()
    {
        for (; counter < 10; )
        {
            //Lock the another thread to enter in critial area
            lock (locker)
            {
                if (counter % 2 == 0)
                {
                    Console.WriteLine(counter);  
                    counter++;
                }
            }
        }
    }
}

使用双线程打印c中的偶数和奇数,即偶数线程和奇数线程

如果您想在两个线程之间交替,可以使用两个AutoResetEvent对象来执行此操作,如下所示:

public static void oddThread()
{
    for (int i = 1; i < 10; i +=2)
    {
        evenReady.WaitOne();
        Console.WriteLine(i);
        oddReady.Set();
    }
}
public static void evenThread()
{
    for (int i = 0; i < 10; i += 2)
    {
        oddReady.WaitOne();
        Console.WriteLine(i);
        evenReady.Set();
    }
}

如果只想运行其中一个线程,则可以使用ManualResetEvent来有效地移除所有锁定。

一个完整的例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Dmr.Common.Resources;
namespace Demo
{
    class Program
    {
        static EventWaitHandle evenReady;
        static EventWaitHandle oddReady;
        static void Main(string[] args)
        {
            bool countOdd  = true; // Change these to true/false as wanted.
            bool countEven = true;
            if (countOdd && countEven)
            {
                evenReady = new AutoResetEvent(false);
                oddReady  = new AutoResetEvent(true); // Must be true for the starting thread.
            }
            else
            {
                evenReady = new ManualResetEvent(true);
                oddReady  = new ManualResetEvent(true);
            }
            Thread countThreadOdd = new Thread(oddThread);
            Thread countThreadEven = new Thread(evenThread);
            //Thread Start
            if (countOdd)
                countThreadOdd.Start();
            if (countEven)
                countThreadEven.Start();
            //main thread will untill below thread is in exection mode
            if (countOdd)
                countThreadOdd.Join();
            if (countEven)
                countThreadEven.Join();
            Console.WriteLine("Done");
            Console.ReadLine();
        }
        public static void oddThread()
        {
            for (int i = 1; i < 10; i +=2)
            {
                evenReady.WaitOne();
                Console.WriteLine(i);
                oddReady.Set();
            }
        }
        public static void evenThread()
        {
            for (int i = 0; i < 10; i += 2)
            {
                oddReady.WaitOne();
                Console.WriteLine(i);
                evenReady.Set();
            }
        }
    }
}

您实际上可以使用Interlocked在线程之间进行通信。Interlocked允许您在两个线程之间同时共享一个变量。

using System;
using System.Threading;
using System.Threading.Tasks;
namespace InterlockedTest
{
    class Program
    {
        private static long _counter = 0;
        private static void printEvenTask()
        {
            while (Interlocked.Read(ref _counter) < 100)
            {
                if (Interlocked.Read(ref _counter) % 2 == 0)
                {
                    Console.WriteLine(Interlocked.Read(ref _counter));
                    Interlocked.Increment(ref _counter);
                }
            }
        }
        private static void printOddTask()
        {
            while (Interlocked.Read(ref _counter) < 100)
            {
                if (Interlocked.Read(ref _counter) % 2 == 1)
                {
                    Console.WriteLine(Interlocked.Read(ref _counter));
                    Interlocked.Increment(ref _counter);
                }
            }
        }
        static void Main(string[] args)
        {
            Task oddTask = Task.Run(() => printOddTask());
            Task evenTask = Task.Run(() => printEvenTask());
            oddTask.Wait();
            evenTask.Wait();
            Console.ReadKey();
        }
    }
}
    static AutoResetEvent evenReady = new AutoResetEvent(true);
    static AutoResetEvent oddReady = new AutoResetEvent(false);
    static void Main()
    {
        Thread countThreadOdd = new Thread(oddThread);
        Thread countThreadEven = new Thread(evenThread);
        countThreadOdd.Start();
        countThreadEven.Start();
        Console.WriteLine("Done");
        Console.ReadLine();
    }
    public static void oddThread()
    {
        for (int i = 1; i < 10; i += 2)
        {              
            oddReady.Set();
            evenReady.WaitOne();
            Console.WriteLine("Odd Thread: " + i);             
            //oddReady.Set();
        }
    }
    public static void evenThread()
    {
        for (int i = 0; i < 10; i += 2)
        {
            oddReady.WaitOne();
            evenReady.Set();
            Console.WriteLine("Even Thread: " + i);               
        }
    }

我们可以使用共享资源(本例中为整数变量)和Task.Delay(1)来实现这一点,这将允许循环暂停一段时间。

完整程序:

internal class Program
{
    int counter = 1;
    static void Main(string[] args)
    {
        var P = new Program();
        var t1 = P.OddThread();
        var t2 = P.EvenThread();
        //Wait for all task to complete
        Task.WaitAll(t1, t2);
        Console.ReadKey();
    }
    public async Task OddThread()
    {
        while (counter < 10)
        {
            // This delay will allow thread to switch and loop will be paused for some time.
            await Task.Delay(1);
            //counter is shared between threads, increment the value if it is odd number
            if (counter % 2 != 0)
            {
                Console.WriteLine(counter);
                counter++;
            }
        }
    }
    //Even Thread
    public async Task EvenThread()
    {
        while (counter < 10)
        {
            // This delay will allow thread to switch and loop will be paused for some time.
            await Task.Delay(1);
            //counter is shared between threads, increment the value if it is even number
            if (counter % 2 == 0)
            {
                Console.WriteLine(counter);
                counter++;
            }
        }
    }

试试这个方法。它使用任务库。

public class OddEvenThread
{
    public static async Task printEvenNumber(int n)
    {
        for (int i = 1; i <= n; i++) 
        {
            if (i % 2 == 0)
             Console.WriteLine(i);
        }
        await Task.Delay(0);
    }
    private static async Task printOddNumbers(int n)
    {
        for (int i = 1; i <= n; i++)
        {
            if (i % 2 == 1)
                Console.WriteLine(i);
        }
        await Task.Delay(0);
    }
    public async static Task printNumbers(int n)
    {
        Task evenNumbers = printEvenNumber(n);
        Task oddNumbers = printOddNumbers(n);
        List<Task> tasks = new List<Task>() { evenNumbers, oddNumbers };
       await Task.WhenAll(tasks);
    }
}

使用AutoResetEvent,线程可以相互等待。这里,两个线程写入从1到20的数字:

using System;
using System.Threading;
namespace oddeven
{
    class Program
    {
        static void Main(string[] args)
        {
            C c = new C();
            Thread t1 = new Thread(c.PrintOdd);
            Thread t2 = new Thread(c.PrintEven);
            t1.Start();
            t2.Start();
        }
    }
    class C
    { 
        AutoResetEvent e1 = new AutoResetEvent(true);
        AutoResetEvent e2 = new AutoResetEvent(true);
        int j = 1;
        public void PrintOdd()
        {
            while (j < 20)
            {
                if (j % 2 != 0)
                {
                    Console.WriteLine(j);
                    j++;
                }
                e1.Set();
                e2.WaitOne();
            }
        }
        public void PrintEven()
        {
            while (j <= 20)
            {
                e1.WaitOne();
                if (j % 2 == 0)
                {
                    Console.WriteLine(j);
                    j++;
                }
                e2.Set();
            }
        }
    }
}

为了实现两个线程之间的线程同步,我们在c#中有多种机制,如ManualResetEvent、AutoResetEvent和Task Parallel Library等。

对于DEMO,我使用自动重置事件

using System;
using System.Threading;
namespace ConsoleApp1
{
    class Program
    {
        public static AutoResetEvent are1 = new AutoResetEvent(false);
        public static AutoResetEvent are2 = new AutoResetEvent(false);
        public static int index=1;
        static void Main(string[] args)
        {
            //Thread to print odd numbers
            Thread tOdd = new Thread(PrintOdd);
            //Thread to print even numbers
            Thread tEven = new Thread(PrintEven);
            tOdd.Start();
            tEven.Start();
            Console.ReadKey();
        }
        static void PrintOdd()
        {
           while(index<=100)
            {
                Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {index++}");
                //sending a signal to print even number
                are2.Set();
                //block to print odd numbers and wait for getting a signal to print odd even number
                are1.WaitOne();
            }
        }
        static void PrintEven()
        {
            while (index <= 100)
            {
                //wait for getting a signal to print an even number
                are2.WaitOne();
                Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: {index++}");
                //sending a signal to print an even number
                are1.Set();
            }
        }
    }
}