C#:如何使用Thread并知道什么时候完成线程工作?

Ela*_*ahe 3 c# multithreading threadpool

我在C#win表单项目中阅读了UNSEEN电子邮件.有些时候有附加文件,下载有一些时间,所以我的项目的UI将在下载完成期间锁定.我使用ThreadPool来解决这个问题.

这是我的代码:

    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();
            }

        }));
    });
Run Code Online (Sandbox Code Playgroud)

这是我使用的Get方法:

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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

正如你在上面的代码中看到的那样,我完全在线程工作完成时有一个动作.实际上,我想告知完成线程工作.

但问题出在这里:大多数时候,当我想从收件箱中获取邮件时,我遇到了这个例外.

The Read method cannot be called when another read operation is pending
Run Code Online (Sandbox Code Playgroud)

如果我删除将运行良好的线程池.我使用threadPool只是为了忽略UI锁定,也知道线程已完成.

有什么更好的方法可以建议我吗?谢谢你的帮助......

nig*_*der 5

有什么更好的方法可以建议吗?

以下是我在WPF应用程序中以现代方式(不再是,如果你在2020年阅读)方法的方法:

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));
}
Run Code Online (Sandbox Code Playgroud)

传递给Task.Run()方法的lambda表达式中的代码将在另一个线程上执行.
在创建和运行任务之后,控制流将直接返回给调用者(在我们的情况下最终返回到UI消息循环,这将继续处理其他事件).
当任务完成时,会向应用程序的消息队列发送一些"唤醒"消息,并且当消息循环接收并处理此消息时,执行将在停止的位置继续执行.
在我们的例子中,当任务完成时,将在"await Task.Run()"call()之后的下一行的主线程上继续执行.
因此命令对象将被启用(它将被绑定到一个按钮,让我们说"下载电子邮件",这样按钮也将被启用),并显示消息框,说明将下载多少封电子邮件.

正如您所看到的,代码非常干净且易于阅读和理解(一旦您了解了使用async/await关键字和Task类的基础知识).

(也请阅读上面关于异常处理的评论)