C #: How to use Thread and know when thread processing has finished?

I am reading an email from UNSEEN in my C # win form draft. several times there are file attachments that the download is done multiple times, so my project interface will block while the download is complete. I am using ThreadPool to solve this problem.

here is my code:

    System.Threading.ThreadPool.QueueUserWorkItem((o) =>
    {
        for (int i = 0; i < lstEmailAddress.Count; i++)
        {
            Get(imap[i], lstEmailAddress[i].MailBox, out Emails[i]);
        }

        this.BeginInvoke(new Action(() =>
        {
            for (int i = 0; i < lstEmailAddress.Count; i++)
            {
                for (int j = 0; j < Emails[i].Count; j++)
                {
                    Database.EmailRecieve_Insert(Emails[i][j]);
                }

                arrEmailUserControl[i].txtRecievedCount.Text = (Convert.ToInt32(arrEmailUserControl[i].txtRecievedCount.Text) + Emails[i].Count).ToString();
            }

        }));
    });

      

here's the Get method I used:

private bool Get(Imap4Client imap, string[,] MailBox, out List<EmailStruct> Emails)
    {
        Emails = new List<EmailStruct>();
        try
        {
            for (int i = 0; i < MailBox.GetLength(0); i++)
            {
                Mailbox inbox = imap.SelectMailbox(MailBox[i, 1]);

                int[] ids = inbox.Search("UNSEEN");

                if (ids.Length > 0)
                {
                    ActiveUp.Net.Mail.Message msg = null;

                    for (var j = 0; j < ids.Length; j++)
                    {
                        msg = inbox.Fetch.MessageObject(ids[j]);

                        EmailStruct email = new EmailStruct();
                        email.SourceAddress = msg.From.Email;
                        email.Subject = msg.Subject;
                        email.Text = msg.BodyText.Text.ToString();

                        msg.Attachments.StoreToFolder(InternalConstant.AttachmentFolder);

                        email.MailBoxID = Convert.ToInt32(MailBox[i, 0]);

                        Emails.Add(email);
                    }
                }
            }
            return true;
        }
        catch (Exception)
        {
            return false;
        }
    }

      

As you can see in the above code, I have an action exactly when the thread is running. Actually, I want to report a thread termination.

but the problem is here: in most cases, I got this exception when I want to receive messages from my inbox.

The Read method cannot be called when another read operation is pending

      

if i remove the threadpool that works well. Im using the threadPool just to ignore the UI lock and also knowing that the thread has finished.

Is there a better way you can suggest me? Thanks for any help ...

+3


source to share


1 answer


Is there a better way you can suggest?

This is how I would do it in a modern (no more if you read it in 2020) in my WPF application:

private async void DoSomethingAsync()
{
    try
    {
        DoanloadEmailsCommand.IsEnabled = false;

        await Task.Run(() =>
        {
            // Do something here. For example, work with the database, download emails, etc.
            Emails = DownloadEmails();
        });
    }
    finally
    {
        DoanloadEmailsCommand.IsEnabled = true;
    }

    MessageBox.Show(string.Format("{0} emails have been downloaded.", Emails.Count));
}

      



The code inside the lambda expression passed to the Task.Run () method will execute on a different thread.
As soon as the task is created and started, the control flow will be returned back to the caller (in our case, eventually to the UI message loop, which will continue to process other events).
When the task completes, some "wake up" message is sent to the application's message queue, and when the message loop receives and processes this message, execution will continue where it left off.
In our case, when the task completes, execution will continue on the main thread from the next line after calling "Waiting for Task.Run () to be called" ().
This way, the command object will be enabled (it will be bound to a button, say, "Download Emails", so the button will also be enabled) and a window will pop up telling you how many emails will be downloaded.

As you can see, the code is pretty clean and easy to read and understand (once you know the basics of using the async / await keywords and the Task class).

(also read my comment above about your exception handling)

+5


source







All Articles