2013-11-29 69 views
0

我的應用程序有一個登錄區域,它使用線程訪問數據庫以不凍結UI。線程競賽和鎖定關鍵字

在登錄過程中,系統進行一些操作以打開主窗口,並將用戶數據(和權限)加載到另一個線程中。

但有時候,當數據庫掛起時,系統在加載用戶之前完成加載。

系統執行的最後一個操作是應用權限(在線程中用用戶數據加載)。

我也有一個靜態的User對象,它保存了登錄用戶的數據,就像它的權限等一樣。

當應用程序在加載用戶之前從靜態用戶對象獲取數據時,會發生此問題。權限是空的,並且沒有正確應用,導致不希望的行爲。

如何確保靜態用戶已加載,並且在網絡/數據庫延遲的極端情況下它只會凍結UI?

我試過使用lock,但它根本不起作用。

這是我的代碼:

int id = User.GetId(user, password); // returns 0 if the user does not exists 

if (id != 0) 
{ 
    new Thread(() => 
    { 
      lock (User.CurrentUser) // Try to lock the static CurrentUser object 
      { 
       User.LoadCurrentUser(id); // Loads the CurrentUser object 
      } 

     }).Start(); 

     InitializeSystem(); //Make some work on the system. After that, this 
          //will get the User.CurrentUser object to apply the 
          //user's permissions. 
    } 

的方法User.LoadCurrentUser(id);填充用戶。

我知道該鎖不起作用,因爲我在鎖內放了一個Thread.Sleep(5000);,系統在2秒內以錯誤的權限啓動。

不考慮刪除線程,因爲它會破壞我的用戶界面。

編輯

我需要使用.Net框架4.0,以確保Windows XP中的兼容性。

回答

1

這是await或鏈式任務的完美人選。

等待版本:

async void YourLoginButtonEventHandler() { 
    int id = User.GetId(user, password); // returns 0 if the user does not exists 

    if (id != 0) { 
     await Task.Run(() => User.LoadCurrentUser(id)); // Loads the CurrentUser object 
     InitializeSystem(); 
    } 
} 

,或者你可以把它們連:

if (id != 0) { 
    Task.Run(() => User.LoadCurrentUser(id)) 
     .ContinueWith(t => InitializeSystem(), TaskScheduler.FromCurrentSynchronizationContext); 
} 

注:可能是一對夫婦的語法錯誤。我打字這個直進到這裏。

我基本上試圖向你展示的是......你正在走這個艱難的路。有更新的構造這種事情..學習它們:)

+0

謝謝。不幸的是,我的應用程序使用.net framework 4.0,因爲它需要在一些Windows XP機器上工作。第二種解決方案適用於4.0? – Guilherme

+0

它確實..但是,語法可能有點不同。例如,我不認爲.NET 4有'Task.Run(Action)'.. –

+0

mmm,第二個解決方案將在User.LoadCurrentUser(id)的同時啓動InitializeSystem()?因爲我在InitializeSystem()上有一些無法凍結的UI操作。 – Guilherme

0

您可以使用Thread.Join來阻止您的主線程,直到其他線程完成或超時。

int id = User.GetId(user, password); // returns 0 if the user does not exists 

if (id != 0) 
{ 
var newThread = new Thread(() => 
{ 
     lock (User.CurrentUser) // Try to lock the static CurrentUser object 
     { 
      User.LoadCurrentUser(id); // Loads the CurrentUser object 
     } 

    }).Start(); 

    InitializeSystem(); 

    if (newThread.Join(someTimeOut)) 
    // use the User.CurrentUser object to apply the user's permissions. 
    else 
    // thread timed out, waiting for user load takes too long... 

} 
+0

很好的答案。問題:線程超時是否立即發生,或者在等待線程完成時鎖定Dispatcher一段時間?當Dispathcer Thread完成其工作時,如果新線程未完成,它似乎立即超時。如果我錯了,它可以等待超時之前多少次?因爲我不能簡單地超時。我需要等到用戶加載完畢,無論它消耗多少時間。 – Guilherme

+0

如果在調用Join時線程已經終止,則該方法立即返回。那麼,如果你說你必須等待,那麼你可以將超時設置爲一些模糊的高值......這是沒有意義的。你需要有一條規則,如果用戶在30秒內沒有加載,你需要通知用戶存在問題。 此外,即使您屏蔽,應用程序也將繼續執行標準COM和SendMessage抽取。 – 2013-11-29 04:57:34

+0

如何在這種情況下設置超時? – Guilherme