Reputation: 5341
My application has a login area that accesses the database using a thread to do not freeze the UI.
During the login, the system makes some operations to open the main window, and loads the user data (and permissions) in the other thread.
But sometimes, when the database hangs, the system finishes loading before the user is loaded.
And the last operation that the system executes is to apply the permissions (loaded in the thread with the user's data).
I also have a static User
object that holds the data of the user that makes the login, like its permissions and so on.
The problem occurs when the application gets the data from the static user object before the user is loaded. The permissions are empty and are not applied correctly, causing undesired behavior.
How can I ensure that the static user is loaded, and it only freezes the UI in extreme cases of network/database latency?
I tried using lock
, but it simply doesn't work.
This is my code:
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.
}
The method User.LoadCurrentUser(id);
fills the User.
I know that the lock is not working because I put a Thread.Sleep(5000);
inside the lock, and the system starts in 2 seconds with the wrong permissions.
Removing the thread is not considered, since it will destroy my UI.
EDIT
I'm need to use .Net Framework 4.0 to ensure Windows XP compatibility.
Upvotes: 0
Views: 78
Reputation:
You can use the Thread.Join to block your main thread until the other thread completes or times out.
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...
}
Upvotes: 0
Reputation: 65079
This is the perfect candidate for await
or chained Tasks.
Await version:
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();
}
}
Or you could chain them:
if (id != 0) {
Task.Run(() => User.LoadCurrentUser(id))
.ContinueWith(t => InitializeSystem(), TaskScheduler.FromCurrentSynchronizationContext);
}
Note: Could be a couple of syntax errors.. I typed this straight into here.
What I'm basically trying to show you is that.. you're going about this the hard way. There are newer constructs for this sort of thing.. learn them :)
Upvotes: 1