我有以下代码:
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/