2015-06-16 100 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實例。