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;