2013-11-29 75 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