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

时间:2015-04-18 04:52:53

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

        }));
    });

这是我使用的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;
        }
    }

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

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

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

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

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

1 个答案:

答案 0 :(得分: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));
}

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

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

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

相关问题