C# 多线程和锁

C# 多线程和锁,c#,multithreading,collections,C#,Multithreading,Collections,我有一个关于多线程的问题 private List<Email> emails = new List<Email>(); private void AddEmail(Email email) { lock (this.emails) { this.emails.Add(email); } } private void ReadEmails() {

我有一个关于多线程的问题

    private List<Email> emails = new List<Email>();

    private void AddEmail(Email email)
    {
        lock (this.emails)
        {
            this.emails.Add(email);
        }
    }

    private void ReadEmails()
    {
        foreach (Email email in this.emails)
        {
            Print(email);
        }
    }
private List emails=new List();
私人邮件(电子邮件)
{
锁(这个。电子邮件)
{
这个.email.Add(email);
}
}
私有无效读邮件()
{
foreach(此.emails中的电子邮件)
{
打印(电子邮件);
}
}

假设ReadEmails方法持续10秒,此时调用AddEmail。那么会发生错误吗?

您肯定应该在Read方法中添加Lock方法。如果不这样做,则可能会在阅读过程尚未完成时添加电子邮件。由于foreach方法要求其集合在迭代期间不可更改,因此将引发异常

 private void ReadEmails()
    {
        lock(emails) {
             foreach (Email email in this.emails) {
                Print(email);
             }
        }
    }

您的
ReadEmails
方法不是线程安全的。你有两个选择

选项#1:

您可以在整个
foreach
循环周围放置

private void ReadEmails()
{
  lock (emails)
  {
    foreach (Email email in this.emails)
    {
      Print(email);
    }
  }
}
选项2:

您可以在
锁中复制列表。然后您可以无锁地迭代复制

private void ReadEmails()
{
  List<Email> copy;
  lock (emails)
  {
    copy = new List<Email>(this.emails);
  }
  foreach (Email email in copy)
  {
    Print(email);
  }
}
private void ReadEmails()
{
清单副本;
锁定(电子邮件)
{
复制=新列表(此为.email);
}
foreach(电子邮件副本)
{
打印(电子邮件);
}
}

如果不告诉我们这应该是什么语言,就不可能回答这个问题——所发生的事情完全取决于实现。+1不过,有一点建议@Bac,最佳做法是使用不同的对象进行锁定,如
私有只读对象_locker=new object()并锁定该对象…公平地说,
电子邮件
已经声明为私有,因此在这种情况下使用不同的对象不会为您带来很多好处。