c# - 这个线程安全吗?多次命中断点

标签 c# multithreading

我有以下代码:

public class EmailJobQueue
{
    private EmailJobQueue()
    {

    }

    private static readonly object JobsLocker = new object();
    private static readonly Queue<EmailJob> Jobs = new Queue<EmailJob>();

    private static readonly object ErroredIdsLocker = new object();
    private static readonly List<long> ErroredIds = new List<long>();

    public static EmailJob GetNextJob()
    {
        lock (JobsLocker)
        {
            lock (ErroredIdsLocker)
            {
                // If there are no jobs or they have all errored then get some new ones - if jobs have previously been skipped then this will re get them
                if (!Jobs.Any() || Jobs.All(j => ErroredIds.Contains(j.Id)))
                {
                    var db = new DBDataContext();
                    foreach (var emailJob in db.Emailing_SelectSend(1))
                    {
                        // Dont re add jobs that exist
                        if (Jobs.All(j => j.Id != emailJob.Id) && !ErroredIds.Contains(emailJob.Id))
                        {
                            Jobs.Enqueue(new EmailJob(emailJob));
                        }
                    }
                }

                while (Jobs.Any())
                {
                    var curJob = Jobs.Dequeue();
                    // Check the job has not previously errored - if they all have then eventually we will exit the loop
                    if (!ErroredIds.Contains(curJob.Id))
                        return curJob;
                }
                return null;
            }
        }
    }

    public static void ReInsertErrored(long id)
    {
        lock (ErroredIdsLocker)
        {
            ErroredIds.Add(id);
        }
    }
}

然后我启动 10 个线程来执行此操作:

var email = EmailJobQueue.GetNextJob();
if (email != null)
{
     // Breakpoint here
}

问题是,如果我在评论所在的位置放置一个断点并将一项添加到队列中,那么该断点会被多次击中。这是我的代码的问题还是 VS 调试器的特性?

谢谢,

最佳答案

看起来好像您是从数据库中获取作业:

foreach (var emailJob in db.Emailing_SelectSend(1))

该数据库调用是否将记录标记为不可用于 future 查询的部分?如果不是,我相信这就是您多次遇到断点的原因。

例如,如果我将对数据库的调用替换为以下内容,我会看到您的行为。

// MockDB is a static configured as `MockDB.Enqueue(new EmailJob{Id = 1})`

private static IEnumerable<EmailJob> GetJobFromDB()
{
    return new List<EmailJob>{MockDB.Peek()};
}

但是,如果我真的从模拟数据库中出队,它只会遇到一次断点。

private static IEnumerable<EmailJob> GetJobFromDB()
{
    var list = new List<EmailJob>();

    if (MockDB.Any())
        list.Add(MockDB.Dequeue());

    return list;
}

关于c# - 这个线程安全吗?多次命中断点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18389798/

相关文章:

c# - 电视卡申请

c# - 如何使用 PetaPoco 或 NPoco 生成 DDL?

java - 无法正确中断平均线程

C使用信号量和线程打印乒乓球

java - 套接字多线程 - 读取输入流暂停线程

c - Windows 线程的奇怪行为

c# - 参数中 C# 中泛型的问题

c# - System.Security.Claims 缺失

c# - SendGrid 给邮件添加类别

c - 以亚微秒频率同步线程和测量性能的最佳方法