如何在使用多线程处理时添加到列表

本文关键字:添加 列表 多线程处理 | 更新日期: 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 类而不是列表。 如果你需要更多的订单,还有一个ConcurrentQueue集合。

如果你真的需要更自定义的东西,你可以使用 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();
        }
    }
}