2011-08-13 39 views
1

我在我的網站上自動執行一些任務,但我目前被卡住了。C#石英比賽條件

public void Execute(JobExecutionContext context) 
    { 
      var linqFindAccount = from Account in MainAccounts 
            where Account.Done == false 
            select Account; 

      foreach (var acc in linqFindAccount) 
      { 
       acc.Done = true; 
       // stuff 
      } 
    } 

的問題是,當我開始多線程第一線程會被分配到相同的第一個帳戶,因爲它們設置在同一時間的完成值設置爲true。我該如何避免這種情況?

編輯:

private object locker = new object(); 

    public void Execute(JobExecutionContext context) 
    { 
     lock (locker) 
     { 
      var linqFindAccount = from Account in MainAccounts 
            where Account.Done == false 
            select Account; 

      foreach (var acc in linqFindAccount) 
      { 
       Console.WriteLine(context.JobDetail.Name + " assigned to " + acc.Mail); 
       acc.Done = true; 
       // stuff 
      } 

     } 
    } 


Instance [ 2 ] assigned to [email protected] 
Instance [ 1 ] assigned to [email protected] 

首先兩個線程得到分配給第一個帳戶,即使列表包含30個賬戶。

謝謝。的

private object locker = new object(); 
+0

你能否給出Execute()方法shoydl究竟acheieve的更多細節?只需更新找到的帳戶的完成屬性?爲什麼你需要多線程呢? – sll

+0

你將要遇到某種鎖對象。看到(可能更好的鏈接,但這是我發現的第一個)http://stackoverflow.com/questions/779533/thread-safety-object-static-or-not – Eddy

+0

@sllev我更新完成的帳戶的屬性,問題是我同時啓動了大約20個線程,並且第2-3個線程被分配到相同的第一個帳戶,因爲他們同時啓動並且在第一個帳戶中完成值設置爲false。時間,我需要多線程,因爲它更快。 – mtnoob

回答

1

使用

private static readonly object locker = new object(); 

,而不是你的問題是,當你開始foreach循環的延遲執行情況。所以結果被緩存,並且不會在每個循環中重新評估。所以每個線程都會使用它自己的項目列表。所以當一個帳戶設置完成時,另一個列表仍然保留在其中的對象。

A Queue更適合這種情況。只需將這些項目放在共享的Queue中,讓循環獲取隊列中的項目,並在Queue爲空時讓它們完成。

+0

此鏈接可能是有用的http://stackoverflow.com/questions/5053172/why-does-the-lock -object-has-to-be-static –

+0

然後只有一個線程能夠訪問循環。 – mtnoob

+0

而這將打破多線程的目的...... – Dmitry

0

0

幾個問題與您的代碼:

1)假設你使用無狀態的石英工作,你的鎖沒有任何好處。 Quartz每次觸發觸發器都會創建新的作業實例。這就是爲什麼你看到相同的帳戶處理兩次。如果你使用有狀態的工作(IStatefulJob),它纔會起作用。或者讓鎖定靜態,但繼續閱讀。

2)即使1)是固定的,它也會失去擁有多個線程的目的,因爲它們都將在同一個鎖上等待對方。你可能有一個線程正在做這個。

我不太瞭解需求,尤其是// stuff中發生了什麼。也許你不需要這個代碼在多個線程上運行,順序執行就可以。我認爲這不是這種情況,你想運行它多個線程。最簡單的方法是隻有一個Quartz作業。在這個工作中,以塊的形式加載賬戶,在每個塊中說100個工作。如果你有500個賬戶,這會給你5個塊。將每個塊處理卸載到thread pool。它會照顧使用最佳線程數。這將是一個窮人的生產者消費者隊列。

public void Execute(JobExecutionContext context) { 

    var linqFindAccount = from Account in MainAccounts 
          where Account.Done == false 
          select Account; 
    IList<IList<Account>> chunks = linqFindAccount.SplitIntoChunks(/* TODO */); 

    foreach (IList<Account> chunk in chunks) { 
     ThreadPool.QueueUserWorkItem(DoStuff, chunk); 
    } 
} 

private static void DoStuff(Object parameter) { 
    IList<Account> chunk = (IList<Account>) parameter; 

    foreach (Account account in chunk) { 
     // stuff 
    } 
} 

像往常一樣,多線程你必須非常小心訪問可變共享狀態。您必須確保您在「DoStuff」方法中執行的所有操作都不會導致不良副作用。您可能會發現thisthis有用。

0
foreach (var acc in linqFindAccount) 
     { 
      string mailComponent = acc.Mail; 
      Console.WriteLine(context.JobDetail.Name + " assigned to " + mailComponent); 
      acc.Done = true; 
      // stuff 
     } 

請嘗試以上。