Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this thread safe? Breakpoints get hit multiple times

I have the following code:

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);
        }
    }
}

I then start 10 threads which do this:

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

The thing is that if I put a breakpoint where the comment is and add one item to the queue then the breakpoint gets hit multiple times. Is this an issue with my code or a peculiarity with VS debugger?

Thanks,

Joe

like image 787
JoeS Avatar asked Mar 03 '26 14:03

JoeS


2 Answers

It appears as if you are getting your jobs from the database:

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

Is that database call marking the records as unavailable for section in future queries? If not, I believe that's why you're hitting the break point multiple times.

For example, if I replace that call to the database with the following, I see your behavior.

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

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

However, if I actually Dequeue from the mock db, it only hits the breakpoint once.

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

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

    return list;
}
like image 114
Greg Avatar answered Mar 05 '26 02:03

Greg


This is a side effect of debugging a multi-threaded piece of your application.

You are seeing the breakpoint being hit on each thread. Debugging a multi-threaded piece of the application is tricky because you're actually debugging all threads at the same time. In fact, at times, it will jump between classes while you're stepping through because it's doing different things on all of those threads, depending on your application.

Now, to address whether or not it's thread-safe. That really depends on how you're using the resources on those threads. If you're just reading, it's likely that it's thread-safe. But if you're writing, you'll need to leverage at least the lock operation on shared objects:

lock (someLockObject)
{
    // perform the write operation
}
like image 35
Mike Perrenoud Avatar answered Mar 05 '26 04:03

Mike Perrenoud



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!