C#Threading:在不正确的对象上执行的线程

时间:2015-06-16 10:11:16

标签: c# multithreading

这可能是我的一个愚蠢的错误,但我无法理解。

所以场景是我每200ms从数据库中检索一条记录,如果有的话。 在每条记录上,我开始一个线程。 在这种情况下,它是一封发送的邮件。

    QMail mailRecord;

    while (!stopSending)
    {

        if (QueueMailingHandler.m_numActive >= MaxThreads)
        {
            Thread.Sleep(2000);
            continue;
        }

        mailRecord = QMail.Next();

        if (mailRecord.UID > 0)
        {
            QueueMailingHandler.m_numActive++;

            QueueMailingHandler MailingHandler = new QueueMailingHandler();

            mailRecord.Processing = true;

            MailingHandler.Start(mailRecord);
        }

        Thread.Sleep(200);
    }

My MailingHandler:

internal QueueMailingHandler()
{
}

internal void Start(QMail rec)
{
    record = rec;
    Thread thread = new Thread(new ThreadStart(ProcessThread));

    thread.IsBackground = true;

    thread.Start();
}

public void ProcessThread()
{
    _logging = new AutoQueueLog(record.UID.ToString(), "Sending Mails", record.Subject, "Processing");
    _logging.Path = @"C:\Windows Services\QueueMailing\AutoLog";
    _logging.LogMessage();
    try
    {

        SendMail(record);
        record.SetDone();
        _logging.State = "Done";
        _logging.LogMessage();
    }
    catch (Exception ex)
    {
        _logging.State = "Error";
        _logging.LogException = ex;
        _logging.Level = AutoLog.ExceptionLevel.Major;
        _logging.LogMessage();
    }
    finally
    {
        m_numActive--;
    }
}

作为伐木结果,我明白了:

6/16/2015 11:57:02 AM - [328] - Function : QueueMailingHandler.ProcessThread() - Processing
6/16/2015 11:57:02 AM - [329] - Function : QueueMailingHandler.ProcessThread() - Processing
6/16/2015 11:57:02 AM - [329] - Function : QueueMailingHandler.ProcessThread() - Done
6/16/2015 11:57:02 AM - [330] - Function : QueueMailingHandler.ProcessThread() - Done
6/16/2015 11:57:02 AM - [330] - Function : QueueMailingHandler.ProcessThread() - Processing
6/16/2015 11:57:02 AM - [331] - Function : QueueMailingHandler.ProcessThread() - Processing
6/16/2015 11:57:02 AM - [331] - Function : QueueMailingHandler.ProcessThread() - Done
6/16/2015 11:57:03 AM - [332] - Function : QueueMailingHandler.ProcessThread() - Processing
6/16/2015 11:57:03 AM - [333] - Function : QueueMailingHandler.ProcessThread() - Processing
6/16/2015 11:57:03 AM - [333] - Function : QueueMailingHandler.ProcessThread() - Done
6/16/2015 11:57:03 AM - [333] - Function : QueueMailingHandler.ProcessThread() - Done
6/16/2015 11:57:03 AM - [333] - Function : QueueMailingHandler.ProcessThread() - Done

问题是:为什么我的线程使用的对象应该是一个单独的(但类似的)线程?

欢迎任何帮助。感谢

2 个答案:

答案 0 :(得分:1)

这是因为您为所有主题使用了record的相同共享实例。

解决问题的一种简单方法是在启动线程时使用参数:

internal void Start(QMail rec)
{
    Thread thread = new Thread(new ParameterizedThreadStart(ProcessThread));

    thread.IsBackground = true;

    thread.Start(rec);
}

然后,在线程中,使用参数而不是属性:

public void ProcessThread(object parameter)
{
    var record = (QMail)parameter;

    _logging = new AutoQueueLog(record.UID.ToString(), "Sending Mails", record.Subject, "Processing");
    _logging.Path = @"C:\Windows Services\QueueMailing\AutoLog";
    _logging.LogMessage();
    try
    {

        SendMail(record);
        record.SetDone();
        _logging.State = "Done";
        _logging.LogMessage();
    }
    catch (Exception ex)
    {
        _logging.State = "Error";
        _logging.LogException = ex;
        _logging.Level = AutoLog.ExceptionLevel.Major;
        _logging.LogMessage();
    }
    finally
    {
        m_numActive--;
    }
}

此外,以这种方式减少m_numActive计数器将产生不可预测的结果。您应该使用线程安全的方法,例如Interlock.Decrement方法:

Interlocked.Decrement(ref m_numActive);

最后但同样重要的是,您应该考虑每次使用线程池而不是创建新线程:

ThreadPool.QueueUserWorkItem(ProcessThread, rec);

答案 1 :(得分:0)

而不是这个

 QMail mailRecord;

while (!stopSending)
{

    if (QueueMailingHandler.m_numActive >= MaxThreads)
    {
        Thread.Sleep(2000);
        continue;
    }

    mailRecord = QMail.Next();

    if (mailRecord.UID > 0)
    {
        QueueMailingHandler.m_numActive++;

        QueueMailingHandler MailingHandler = new QueueMailingHandler();

        mailRecord.Processing = true;

        MailingHandler.Start(mailRecord);
    }

    Thread.Sleep(200);
}

试试这个

while (!stopSending)
{

    if (QueueMailingHandler.m_numActive >= MaxThreads)
    {
        Thread.Sleep(2000);
        continue;
    }

    QMail mailRecord = QMail.Next();

    if (mailRecord.UID > 0)
    {
        QueueMailingHandler.m_numActive++;

        QueueMailingHandler MailingHandler = new QueueMailingHandler();

        mailRecord.Processing = true;

        MailingHandler.Start(mailRecord);
    }

    Thread.Sleep(200);
}

这里唯一的区别就是你声明你的QMail实例。