C# 顺序多线程

C# 顺序多线程,c#,multithreading,sequence,C#,Multithreading,Sequence,我有一个主要任务,就是生成线程来做一些工作。当工作完成时,它将写入控制台 我的问题是,一些稍后创建的线程将比先前创建的线程完成得更快。但是,我需要按照创建线程的相同顺序写入控制台 因此,如果一个线程已经完成了它的任务,而一些早期线程还没有完成,那么它必须等待这些早期线程也完成 public class DoRead { public DoRead() { } private void StartReading()

我有一个主要任务,就是生成线程来做一些工作。当工作完成时,它将写入控制台

我的问题是,一些稍后创建的线程将比先前创建的线程完成得更快。但是,我需要按照创建线程的相同顺序写入控制台

因此,如果一个线程已经完成了它的任务,而一些早期线程还没有完成,那么它必须等待这些早期线程也完成

    public class DoRead
    {
        public DoRead()
        {
        }

        private void StartReading()
        {
            int i = 1;

            while (i < 10000)
            {
                Runner r = new Runner(i, "Work" + i.ToString());
                r.StartThread();
                i += 1;
            }
        }
    }

    internal class Runner : System.IDisposable
    {
        int _count;
        string _work = "";

        public Runner(int Count, string Work)
        {
            _count = Count;
            _work = Work;
        }

        public void StartThread()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(runThreadInPool), this);
        }

        public static void runThreadInPool(object obj)
        {
            ((Runner)obj).run();
        }

        public void run()
        {
            try
            {
                Random r = new Random();
                int num = r.Next(1000, 2000);

                DateTime end = DateTime.Now.AddMilliseconds(num);
                while (end > DateTime.Now)
                {
                }

                Console.WriteLine(_count.ToString() + " : Done!");
            }
            catch
            {
            }
            finally
            {
                 _work = null;
            }
        }

        public void Dispose()
        {
             this._work = null;
        }

    }
公共类数据读取
{
公共数据源()
{
}
私有void startreding()
{
int i=1;
而(i<10000)
{
Runner r=新的Runner(i,“工作”+i.ToString());
r、 StartThread();
i+=1;
}
}
}
内部类运行程序:System.IDisposable
{
整数计数;
字符串_work=“”;
公共运行程序(整数计数、字符串工作)
{
_计数=计数;
_工作=工作;
}
public void StartThread()
{
QueueUserWorkItem(新的WaitCallback(runThreadInPool),this);
}
公共静态void runThreadInPool(对象obj)
{
((转轮)obj.run();
}
公开募捐
{
尝试
{
随机r=新随机();
int num=r.Next(10002000);
DateTime end=DateTime.Now.addmillizes(num);
while(end>DateTime.Now)
{
}
Console.WriteLine(_count.ToString()+“:Done!”);
}
抓住
{
}
最后
{
_工作=空;
}
}
公共空间处置()
{
这是。_work=null;
}
}
我对C#知之甚少,但多线程的整体思想是,您有多个独立执行的线程,您永远不可能知道哪个线程会提前完成(您不应该期望更早的线程提前结束)

一种解决方法是,在处理线程中写入完成消息,让处理线程在某处设置一个标志(可能是一个没有元素的列表=没有生成线程的列表),并让一个单独的线程根据该列表中的标志打印完成消息,并向上一个标志连续“完成”的位置报告

老实说,我觉得你打印这样的完成消息是不合理的。我认为改变设计更好的办法是拥有这种毫无意义的“特性”。

我对C#知之甚少,但多线程的整体思想是,您有多个独立执行的线程,您永远无法知道哪个线程会更早完成(您不应该期望更早的线程更早结束)

一种解决方法是,在处理线程中写入完成消息,让处理线程在某处设置一个标志(可能是一个没有元素的列表=没有生成线程的列表),并让一个单独的线程根据该列表中的标志打印完成消息,并向上一个标志连续“完成”的位置报告


老实说,我觉得你打印这样的完成消息是不合理的。我认为改变设计会更好地拥有这种毫无意义的“功能”。

可能有一种比我以前使用的更简单的方法(我已经习惯了.Net 4.0)


这是线程安全的,因为numTasksLeft是一个在32位或更高的计算机上原子读取的int。

可能有一种比我使用的更简单的方法(我习惯于.Net 4.0)


这是线程安全的,因为numTasksLeft是一个在32位或更高的计算机上原子读取的int。

通常,这些要求通过递增的序列号来满足,就像您已经做的那样

通常,处理线程的输出通过一个过滤器对象提供,该过滤器对象包含所有无序结果对象的列表(或字典),“保留它们”,直到所有序列号较低的结果都进入。同样,与您已经做的类似

不需要的是任何类型的sleep()循环。工作线程本身可以操作过滤器对象(这将是一个锁),或者工作线程可以将结果排队给操作无序过滤器的“输出线程”


此方案适用于合并的工作线程,即那些没有持续创建/终止/销毁开销的线程。

通常,这些需求通过递增的序列号来满足,就像您已经做的那样

通常,处理线程的输出通过一个过滤器对象提供,该过滤器对象包含所有无序结果对象的列表(或字典),“保留它们”,直到所有序列号较低的结果都进入。同样,与您已经做的类似

不需要的是任何类型的sleep()循环。工作线程本身可以操作过滤器对象(这将是一个锁),或者工作线程可以将结果排队给操作无序过滤器的“输出线程”


此方案适用于池工作线程,即那些没有持续创建/终止/销毁开销的线程。

您能使用.net 4.0吗?我问,因为语法会更简洁。不幸的是,我仅限于.net 2.0。您能使用.net 4.0吗?我问,因为语法会更简洁。不幸的是,我仅限于.NET2.0
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ConsoleApplication5
{
    class Program
    {
        public static readonly int numOfTasks = 100;

        public static int numTasksLeft = numOfTasks;

        public static readonly object TaskDecrementLock = new object();

        static void Main(string[] args)
        {
            DoRead dr = new DoRead();

            dr.StartReading();

            int tmpNumTasks = numTasksLeft;

            while ( tmpNumTasks > 0 )
            {
                Thread.Sleep(1000);
                tmpNumTasks = numTasksLeft;
            }


            List<string> strings = new List<string>();

            lock( DoRead.locker )
            {
                for (int i = 1; i <= Program.numOfTasks; i++)
                {
                    strings.Add( DoRead.dicto[i] );
                }
            }

            foreach (string s in strings)
            {
                Console.WriteLine(s);
            }

            Console.ReadLine();
        }

        public class DoRead
        {

            public static readonly object locker = new object();

            public static Dictionary<int, string> dicto = new Dictionary<int, string>();

            public DoRead()
            {
            }

            public void StartReading()
            {
                int i = 1;

                while (i <= Program.numOfTasks )
                {
                    Runner r = new Runner(i, "Work" + i.ToString());
                    r.StartThread();
                    i += 1;
                }


            }
        }

        internal class Runner : System.IDisposable
        {
            int _count;
            string _work = "";

            public Runner(int Count, string Work)
            {
                _count = Count;
                _work = Work;
            }

            public void StartThread()
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(runThreadInPool), this);
            }

            public static void runThreadInPool(object obj)
            {
                Runner theRunner = ((Runner)obj);
                string theString = theRunner.run();

                lock (DoRead.locker)
                {
                    DoRead.dicto.Add( theRunner._count, theString);
                }

                lock (Program.TaskDecrementLock)
                {
                    Program.numTasksLeft--;
                }
            }

            public string run()
            {
                try
                {
                    Random r = new Random();
                    int num = r.Next(1000, 2000);

                    Thread.Sleep(num);

                    string theString = _count.ToString() + " : Done!";

                    return theString;

                }
                catch
                {
                }
                finally
                {
                    _work = null;
                }

                return "";
            }

            public void Dispose()
            {
                this._work = null;
            }

        }
    }
}
 tmpNumTasks = numTasksLeft;