2015-06-16 77 views
2

也许这对我来说是一个愚蠢的错误,但我无法弄清楚。C#线程:在不正确的对象上执行的线程

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

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

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

而作为loggingresult,我得到这个:

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 

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

任何帮助,欢迎。由于

+0

所以你的问题是什么? –

+0

我很乐意提供帮助,但您的问题到底是什么? –

+0

我几乎可以肯定,错误在你的'record = rec'行中。你想复制你的对象,但你只需复制一个引用到原来的引用,所以下一个'record = rec;'会覆盖最后一个。你可以尝试在'rec'上调用copy contructor吗? – mg30rg

回答

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); 
+0

好吧,看起来像这个Start()函数正在做的伎俩。 但是你建议我在这里使用ThreadPool而不是线程。什么是冒险,并且互锁增量还会继续发挥作用吗? –

+0

@ Devcon2线程池是由.NET运行时直接管理的一组线程。它适用于主动创建线程之前的短任务(从而在启动任务时节省创建延迟),并根据机器资源调整活动线程的数量。 Interlocked.Increment/Decrement只是线程安全的操作数字的方法,所以它不会影响您是手动创建线程还是使用线程池 –

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实例。