-1

I'm coding 'Waiting for login' in the app.

    public struct Member
    {
        public bool IsOpened, IsLogIn;
        public string Title, Name;
    }
    private static void WaitForLogin(ref Member member)
    {
        while (member.IsOpened)
        {
            if (IsLoggIn() == true)
            {
                member.Title = "Welcome to App Centrel";
                member.Name = "Omer";
                member.IsLogIn = true;
                break;
            }
            System.Threading.Thread.Sleep(1000);
        }
    }

Using the non-freezing Task, Thread, Async Etc... codes, Time problem occurs due to the ref, out in the parameter. How does the method not freeze until finished using out, ref parameter? External app is the not logged in. started freezing in my UI. I wanted to change the 'mem' variable the time when logged in in the IsLoggIn() method

ÖMER
  • 15
  • 6
  • Is it not possible to return a value instead of modifying a passed parameter? – Zdeněk Jelínek Apr 21 '22 at 11:58
  • 1
    You can run Timer with callback and assign Elapsed event to `WaitForLogin` function, you can also set timer interval to 1000. Anyway, its wrong approach. I would suggest doing logging in functionality on events. – Bartosz Olchowik Apr 21 '22 at 11:59
  • Take a look at `async/await`. `Thread.Sleep()` is doing exactly what it says. If you are in UI thread, the UI thread is going to sleep ;) See comment from feal below – Demetrius Axenowski Apr 21 '22 at 12:02
  • 1
    Why is the Member data a struct. Is that neccessary. Make a class out of it, remove the ref parameter and then use await Task.Delay(1000) for example. – Felix Almesberger Apr 21 '22 at 12:03
  • The topic has been updated. Can you please review again? I wanted to change the 'mem' variable the time when logged in in the IsLoggIn() method. – ÖMER Apr 21 '22 at 12:05

2 Answers2

2

Thread.Sleep(1000) will suspend the current (UI) thread. This is rarely a good idea, especially on the UI thread. Also note that your example code is probably not safe. I would assume that you are modifying the IsOpened field from another thread, and this is not safe without at least marking the field as volatile. But just use a full lock if you are unsure about the level of synchronization needed.

I do not see that the ref has any real effect on the UI freezing. But I would in general recommend against mutable structs. Just use a class with properties instead.

The simplest possible workaround would be to replace the sleep with a Task.Delay and mark the method as async. This will internally be similar to starting a timer that checks for the login. But be careful with async void functions, since they can lose exception if you are not careful. Prefer to return a task for async functions, unless it has to be void, like an event-handler.

A better solution will be to let whatever component doing the login to send an event. This might be a regular event, or it might be thread-safe event, or a waithandle that may be triggered from a separate process if named. You can also use a task to signal the completion of some login process. But it is difficult to tell exactly how this should be done without more information about the internals of the system.

Regardless of the option you pick, you should probably show a modal UI dialog while waiting for login, to prevent any other interaction with the UI while waiting, while still allowing the UI to be responsive.

For example using a task to signal login and winforms for the UI

public static Task ShowDialogUntillLogin(Task loginTask){
    var myForm = new MyForm();
    loginTask.ContinueWith(t => myForm.Invoke(() => myForm.DialogResult = DialogResult.OK));
    myForm.ShowDialog();
    return loginTask;
}

This should show the form until the task is set as complete. When this happens the dialog will be closed and the method returns. Since it blocks inside the ShowDialog method UI messages will still be processed, and the UI remain responsive, but the user can only do stuff in MyForm.

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • Thanks for information about UI Thread. If Method with Thread runs, the variable mem.Name did not change. method skipped. MessageBox.Show(mem.Name); coded message box is showing blank. Showing something in message box with UI freezing problem code. – ÖMER Apr 21 '22 at 12:43
  • @ÖMER I'm sorry but I really do not understand what you mean. However, whenever you are dealing with multiple threads you need to be really careful to ensure the code is threadsafe. If you are not familiar with thread safe programming I would recommend sticking to a single thread. It might also be a good idea to explain what you are *actually* trying to do. – JonasH Apr 21 '22 at 12:47
2

Once again, why you are using struct? Why not like this?

    public class Member
    {
        public bool IsOpened { get; set; } 
        public bool IsLogIn{ get; set; } 
        public string Title{ get; set; } 
        public string Name{ get; set; }
    }
    private static async Task WaitForLogin(Member member)
    {
        while (member.IsOpened)
        {
            if (IsLoggIn() == true)
            {
                member.Title = "Welcome to App Centrel";
                member.Name = "Omer";
                member.IsLogIn = true;
                break;
            }
            await Task.Delay(1000);
        }
    }

Then you should be able to use it like this

private async void button1_Click(object sender, EventArgs e) 
{ 
    Member asD = new Member(); 
    asD.IsOpened = true; 
    await WaitForLogin(asD); 
    MessageBox.Show("Logged In. Starting Methods"); 
}