在单独的线程中调用时,C# 2.0 函数不起作用
Posted
技术标签:
【中文标题】在单独的线程中调用时,C# 2.0 函数不起作用【英文标题】:C# 2.0 Function does not work when call in a separate thread 【发布时间】:2010-10-13 10:38:56 【问题描述】:我有一个功能可以从 DocuShare 服务器下载邮件作为 MSG 文件。当从主线程调用时,该函数可以完美运行。但是,当我在单独的线程中调用该函数时,下载失败。当我进入代码时,我可以看到函数正在被调用,所有参数都被正确评估并且返回值是我所期望的。不幸的是,我明白了,没有文件被下载。
代码:
private void btnDownloadMails_Click(object sender, EventArgs e)
//Thread t = new Thread(new ThreadStart(DownloadMailAsMsg));
//t.Start(); //Does not work
DownloadMailAsMsg(); // Works fine
void DownloadMailAsMsg()
DSServerMap.Server dsserver = new DSServerMap.Server();
if (!SelectMappedServer(ref dsserver, textServer.Text.ToString()))
return;
long status = 0;
dsserver.DocuShareAddress = textServer.Text;
dsserver.UserName = textUser.Text;
dsserver.Password = textPwd.Text;
status = dsserver.Logon();
if (status == 0)
IItemObj objParentItem;
string[] emailHan = "MailMessage-12", "MailMessage-13", "MailMessage-31" ;
foreach (string handnum in emailHan)
objParentItem = (IItemObj)dsserver.CreateObject(handnum);
DSGATEWAYLib.IGatewayHandler gateway = (DSGATEWAYLib.IGatewayHandler)dsserver.Open();
objParentItem.AttachGateway(gateway, true);
objParentItem.Name = @"D:\em\m_" + handnum + ".msg";
int flag = objParentItem.DSDownload(0);
有什么想法吗?
谢谢 普拉卡什
【问题讨论】:
我怀疑这是主要原因,但是:您甚至不应该真正与非 UI 线程上的所有.Text
属性交谈。理想情况下,您应该事先获得它并将其传递给工作人员。
【参考方案1】:
也许您需要一个 STA 线程。我曾经遇到过类似的问题,以下解决了我的问题:
Thread t = new Thread((ThreadStart)delegate
// MAPI does only work in STA threads. Therefore an STA thread needs to be created explicitly for the SendMail call.
//...do work here
);
t.SetApartmentState(ApartmentState.STA);
t.Start();
也许这也能解决你的问题。
【讨论】:
是的,这可能是问题所在。但是一个 STA 线程也需要一个消息循环。 OP 的代码在没有代码的情况下仍然死锁的可能性很大。使用 Application.Run()。 我在 ApartmentState.STA 模式下的线程中调用了该函数,它起作用了。谢谢 testalino。【参考方案2】:您的线程应该是类成员而不是方法变量。
当您的方法完成时,线程变量会超出范围,可能会在未完成的情况下被清理。
【讨论】:
线程是***(根)对象,不会因为变量超出范围而终止。【参考方案3】:您正试图在非 UI 线程中访问 Control 的属性,
例如在行中,
dsserver.DocuShareAddress = textServer.Text;
dsserver.UserName = textUser.Text;
dsserver.Password = textPwd.Text;
您试图在不同的线程中访问 UI 控件的 Text 属性,这实际上会引发异常。
您想在不同线程中访问每个控件的值,您必须将其包装在某种争论中并将其传递给线程。
class MyServerParameters
string Server;
string Username;
string Password;
private void btnDownloadMails_Click(object sender, EventArgs e)
MyServerParameters p = new MyServerParameters();
// we are still in UI thread so copy your values
// to p
p.Server = textServer.Text;
p.Username = textUser.Text;
p.Password = textPwd.Text;
Thread t = new Thread(new ParametricThreadStart(DownloadMailAsMsg));
// pass p to another thread
t.Start(p); // this will work...
void DownloadMailAsMsg(object mp)
// access p back like this...
MyServerParameters p = mp as MyServerParameters;
dsserver.DocuShareAddress = p.Server;
dsserver.UserName = p.Username;
dsserver.Password = p.Password;
【讨论】:
它是准确的,但实际上不是问题所在。 Text 属性很特殊,它正在被缓存,实际上可以从工作线程中读取(但不能写入)。 @Hans,我有疑问,但我还是会检查一下。【参考方案4】:创建控件的.Text
属性的副本,并在第二个线程中仅引用它们。
如果您使用不同的线程访问任何控件,您将锁定您的应用程序或获得异常。
其他方法是使用.Invoke()
,但在你的情况下,你真的不需要去那里。
【讨论】:
以上是关于在单独的线程中调用时,C# 2.0 函数不起作用的主要内容,如果未能解决你的问题,请参考以下文章