如何在使用多线程处理时添加到列表
本文关键字:添加 列表 多线程处理 | 更新日期: 2023-09-27 18:34:16
我对多线程有点陌生,过去只玩过它。但我很好奇是否有可能在主线程上有一个字节数组列表,并且在单独的线程中创建新的字节数组时仍然能够添加到该列表中。 此外,我将使用一个 for-each 循环,该循环将遍历将用于解析为字节数组的表单列表。 所以基本上伪代码是这样的...
reports = new List();
foreach (form in forms)
{
newReport = new Thread(ParseForm(form));
reports.Add(newReport);
}
void ParseForm(form)
{
newArray = new byte[];
newArray = Convert.ToBytes(form);
return newArray;
}
希望上面的伪代码有意义。如果有人能告诉我这是否可能,并指出我一个好例子的方向,我相信我可以找出实际的代码。
在我们意识到它是 .Net 3.5 之前,请在 .Net 4 上保留以供参考
如果你不需要列表中的任何顺序,一个简单的"修复"是使用 ConcurrentBag
如果你真的需要更自定义的东西,你可以使用 BlockingCollection
您也可以使用 Parallel.Foreach 来避免显式创建线程:
private void ParseForms()
{
var reports = new ConcurrentBag<byte[]>();
Parallel.ForEach(forms, (form) =>
{
reports.Add(ParseForm(form));
});
}
private byte[] ParseForm(form)
{
newArray = new byte[];
newArray = Convert.ToBytes(form);
return newArray;
}
如果需要从多个线程访问集合,则应使用同步,或者在 .NET 版本为 3.0 或更高版本时使用SynchronizedCollection
。
下面是使线程可以访问集合的一种方法:
SynchronizedCollection reports = new SynchronizedCollection();
foreach (form in forms) {
var reportThread = new Thread(() => ParseForm(form, reports));
reportThread.Start();
}
void ParseForm(Form form, SynchronizedCollection reports) {
newArray = new byte[];
newArray = Convert.ToBytes(form);
reports.Add(newArray);
}
如果您使用的是 .NET 4 或更高版本,则手动管理线程的更好替代方法是由 System.Threading.Tasks
命名空间的各个类提供。在决定线程实现之前,请考虑探索此替代方法。
为什么枚举文件多次返回同一个文件?
看看吧。 它表明我正是想你想做什么。
它在主线程上创建一个列表,然后从其他线程添加到主线程。您将需要
using System.Threading.Tasks
-
Files.Clear(); //List<string>
Task.Factory.StartNew( () =>
{
this.BeginInvoke( new Action(() =>
{
Files.Add("Hi");
}));
});
下面是一个简单的阻塞集合(仅作为队列),因为您无法访问 C# 4.0,所以我现在刚刚启动了它。 它的效率很可能低于 4.0 并发集合,但它应该运行良好。 我没有重新实现所有 Queue 方法,只是排队、取消排队和偷看。 如果您需要其他人并且无法弄清楚它们将如何实现,请在评论中提及。
获得工作阻塞集合后,只需从生产者线程添加到它,并使用使用者线程从中删除它。
public class MyBlockingQueue<T>
{
private Queue<T> queue = new Queue<T>();
private AutoResetEvent signal = new AutoResetEvent(false);
private object padLock = new object();
public void Enqueue(T item)
{
lock (padLock)
{
queue.Enqueue(item);
signal.Set();
}
}
public T Peek()
{
lock (padLock)
{
while (queue.Count < 1)
{
signal.WaitOne();
}
return queue.Peek();
}
}
public T Dequeue()
{
lock (padLock)
{
while (queue.Count < 1)
{
signal.WaitOne();
}
return queue.Dequeue();
}
}
}