C# C语言中五个线程之间的时间切片

C# C语言中五个线程之间的时间切片,c#,multithreading,file-io,job-scheduling,round-robin,C#,Multithreading,File Io,Job Scheduling,Round Robin,下面是程序应该做什么的描述。程序应该创建一个文件和五个线程来写入该文件 第一个线程应该将1到5写入该文件。 第二个线程应该从1写入到10。 第三个线程应该从1写入到15。 第四个线程应该从1写入到20。 第五个线程应该从1写入到25 此外,应该实现一个算法,使每个线程打印2个数字和停止。下一个线程应该打印两个数字并停止。依此类推,直到所有线程都打印完它们的数字。 这是我到目前为止开发的代码 using System; using System.IO; using System.Threading

下面是程序应该做什么的描述。程序应该创建一个文件和五个线程来写入该文件

第一个线程应该将1到5写入该文件。 第二个线程应该从1写入到10。 第三个线程应该从1写入到15。 第四个线程应该从1写入到20。 第五个线程应该从1写入到25

此外,应该实现一个算法,使每个线程打印2个数字和停止。下一个线程应该打印两个数字并停止。依此类推,直到所有线程都打印完它们的数字。 这是我到目前为止开发的代码

using System;
using System.IO;
using System.Threading;
using System.Collections;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    public static class OSAssignment
    {
        // First Thread Tasks...
        static void FirstThreadTasks(StreamWriter WritingBuffer)
        {
            for (int i = 1; i <= 5; i++)
            {
                if (i % 2 == 0)
                {
                    Console.WriteLine("[Thread1] " + i);
                    Thread.Sleep(i);
                }

                else
                {
                    Console.WriteLine("[Thread1] " + i);
                }
            }
        }

        // Second Thread Tasks...
        static void SecondThreadTasks(StreamWriter WritingBuffer)
        {
            for (int i = 1; i <= 10; i++)
            {
                if (i % 2 == 0)
                {
                    if (i == 10)
                        Console.WriteLine("[Thread2] " + i);

                    else
                    {
                        Console.WriteLine("[Thread2] " + i);
                        Thread.Sleep(i);
                    }
                }

                else
                {
                    Console.WriteLine("[Thread2] " + i);
                }
            }
        }

        // Third Thread Tasks..
        static void ThirdThreadTasks(StreamWriter WritingBuffer)
        {
            for (int i = 1; i <= 15; i++)
            {
                if (i % 2 == 0)
                {
                    Console.WriteLine("[Thread3] " + i);
                    Thread.Sleep(i);
                }

                else
                {
                    Console.WriteLine("[Thread3] " + i);
                }
            }
        }

        // Fourth Thread Tasks...
        static void FourthThreadTasks(StreamWriter WritingBuffer)
        {
            for (int i = 1; i <= 20; i++)
            {
                if (i % 2 == 0)
                {
                    if (i == 20)
                        Console.WriteLine("[Thread4] " + i);
                    else
                    {
                        Console.WriteLine("[Thread4] " + i);
                        Thread.Sleep(i);
                    }
                }

                else
                {
                    Console.WriteLine("[Thread4] " + i);
                }

            }
        }

        // Fifth Thread Tasks...
        static void FifthThreadTasks(StreamWriter WritingBuffer)
        {
            for (int i = 1; i <= 25; i++)
            {
                if (i % 2 == 0)
                {
                    Console.WriteLine("[Thread5] " + i);
                    Thread.Sleep(i);
                }

                else
                {
                    Console.WriteLine("[Thread5] " + i);
                }

            }
        }

        // Main Function...
        static void Main(string[] args)
        {
            FileStream File = new FileStream("output.txt", FileMode.Create, FileAccess.Write, FileShare.Write);
            StreamWriter Writer = new StreamWriter(File);
            Thread T1 = new Thread(() => FirstThreadTasks(Writer));
            Thread T2 = new Thread(() => SecondThreadTasks(Writer));
            Thread T3 = new Thread(() => ThirdThreadTasks(Writer));
            Thread T4 = new Thread(() => FourthThreadTasks(Writer));
            Thread T5 = new Thread(() => FifthThreadTasks(Writer));
            Console.WriteLine("Initiating Jobs...");
            T1.Start();
            T2.Start();
            T3.Start();
            T4.Start();
            T5.Start();
            Writer.Flush();
            Writer.Close();
            File.Close();
        }
    }
}
以下是我面临的问题

即使使用FileShare.write,我也不知道如何让5个线程同时写入同一个文件。所以,我只是决定暂时编写控制台,开发算法,并首先在控制台中查看它的行为

每次我运行程序时,输出都与以前略有不同。通常情况下,一个线程在特定的迭代中只打印它的一个数字,并且在另一个线程完成当前迭代后继续输出第二个数字

我有个问题可能有点离题。如果我移除Console.WriteLineInitiating作业。。。;从main方法来看,算法的行为与我在第2点中提到的不同。我真的不明白为什么

您的主要功能是在线程开始写入文件之前完成并关闭文件,因此您可以使用Thread.Join等待线程退出。我还建议对IDisposable对象使用using语句

当您想要在线程之间共享有限的资源时,您需要一个锁定机制。线程调度是不确定的。您已经启动了5个线程,此时无法保证哪个线程将首先运行。锁将强制线程等待资源释放。订单仍未确定,因此T3可能在T2之前运行,除非您添加额外的逻辑/锁定以强制执行订单

我看不出在行为上有什么不同,但是自由运行的线程会产生一些很难发现的bug,特别是与时间问题有关的bug

另外,我要避免使用睡眠作为同步线程的方式

为了有效地让一个线程一次写入,您需要阻止所有其他线程,有几种方法可以做到这一点,如锁定、互斥、监视、自动resetEvent等。在这种情况下,我会使用自动resetEvent。然后您面临的问题是每个线程都需要知道它正在等待哪个线程,以便它可以等待正确的事件

您的主要功能是在线程开始写入文件之前完成并关闭文件,因此您可以使用Thread.Join等待线程退出。我还建议对IDisposable对象使用using语句

当您想要在线程之间共享有限的资源时,您需要一个锁定机制。线程调度是不确定的。您已经启动了5个线程,此时无法保证哪个线程将首先运行。锁将强制线程等待资源释放。订单仍未确定,因此T3可能在T2之前运行,除非您添加额外的逻辑/锁定以强制执行订单

我看不出在行为上有什么不同,但是自由运行的线程会产生一些很难发现的bug,特别是与时间问题有关的bug

另外,我要避免使用睡眠作为同步线程的方式


为了有效地让一个线程一次写入,您需要阻止所有其他线程,有几种方法可以做到这一点,如锁定、互斥、监视、自动resetEvent等。在这种情况下,我会使用自动resetEvent。然后您面临的问题是,每个线程都需要知道它正在等待哪个线程,以便它可以等待正确的事件。

请参阅James的答案。他指出了我没有注意到的一个关键错误:在编写器线程完成之前关闭文件。考虑一个新的问题来询问如何解决这个问题,因为这个问题已经被归纳为三个问题。

Write告诉操作系统允许其他尝试打开文件进行写入。通常,这用于具有多个进程写入同一文件的系统。在您的例子中,您只有一个进程,它只打开文件一次,所以这个标志实际上没有什么区别。这是做这项工作的错误工具。 要协调多个线程之间的写入,应使用锁定。向类中添加新的静态字段:

private static object synchronizer = new object();
然后将文件上的每个写入操作包装为该对象上的锁:

lock(synchronizer)
{
    Console.WriteLine("[Thread1] " + i);    
}
当您使用控制台时,这不会有什么不同,但我认为它将解决您在写入文件时遇到的问题

说到这里,从文件写入切换到控制台写入以避开文件 这个问题是个聪明的主意,所以值得称赞。然而,更好的实现方法是将所有写调用替换为对单个函数的调用,例如WriteOutputstring,这样您只需更改该函数中的一行即可将所有内容从文件切换到控制台

然后你也可以把锁放在这个功能里

线程化的东西是不确定的。可以保证每个线程都会运行,但不能保证排序、线程何时中断、哪个线程将中断哪个线程等等。每次都是掷骰子。你只需要习惯它,或者如果这对你的应用程序来说真的很重要的话,你就要不遗余力地强迫事情按一定的顺序发生

我不知道这件事。看起来这不重要


请看詹姆斯的回答。他指出了我没有注意到的一个关键错误:在编写器线程完成之前关闭文件。考虑一个新的问题来询问如何解决这个问题,因为这个问题已经被归纳为三个问题。

Write告诉操作系统允许其他尝试打开文件进行写入。通常,这用于具有多个进程写入同一文件的系统。在您的例子中,您只有一个进程,它只打开文件一次,所以这个标志实际上没有什么区别。这是做这项工作的错误工具。 要协调多个线程之间的写入,应使用锁定。向类中添加新的静态字段:

private static object synchronizer = new object();
然后将文件上的每个写入操作包装为该对象上的锁:

lock(synchronizer)
{
    Console.WriteLine("[Thread1] " + i);    
}
当您使用控制台时,这不会有什么不同,但我认为它将解决您在写入文件时遇到的问题

说到这里,从文件写入切换到控制台写入以避免文件问题是一个聪明的想法,因此值得称赞。然而,更好的实现方法是将所有写调用替换为对单个函数的调用,例如WriteOutputstring,这样您只需更改该函数中的一行即可将所有内容从文件切换到控制台

然后你也可以把锁放在这个功能里

线程化的东西是不确定的。可以保证每个线程都会运行,但不能保证排序、线程何时中断、哪个线程将中断哪个线程等等。每次都是掷骰子。你只需要习惯它,或者如果这对你的应用程序来说真的很重要的话,你就要不遗余力地强迫事情按一定的顺序发生

我不知道这件事。看起来这不重要


好的,我讲得比较晚,但从理论上看,从多线程到特定端点的I/O不可避免地令人担忧


在上面的示例中,几乎可以肯定,将输出排队到内存结构中会更快更安全,每个线程在这样做之前都使用一个排他锁,然后有一个单独的线程输出到设备

好吧,我讲得太晚了,但是从理论的角度来看,从多线程到特定端点的I/O不可避免地令人担忧


在上面的示例中,几乎可以肯定,将输出排队到内存结构中会更快更安全,每个线程在这样做之前都使用一个排他锁,然后有一个单独的线程输出到设备

先生,当一个线程在文件中写入时,是否有方法确保其他线程处于非活动状态;从而防止发生中断?锁定就是这样做的。在一个线程获取锁后,下一个或多个试图获取锁的线程将等待锁被释放,当获取锁的线程退出lock{}语句时就会发生这种情况。所以,若你们所有的写操作都在锁同步器中,那个么在任何时候都只有一个线程可以写。另外,我刚刚在我的回答中添加了一个前言-请重新阅读:-先生,当一个线程在文件中写入时,是否有方法确保其他线程处于非活动状态;从而防止发生中断?锁定就是这样做的。在一个线程获取锁后,下一个或多个试图获取锁的线程将等待锁被释放,当获取锁的线程退出lock{}语句时就会发生这种情况。所以,若你们所有的写操作都在锁同步器中,那个么在任何时候都只有一个线程可以写。另外,我刚刚在我的回答中添加了一个前言-请重新阅读:-