在单独的线程中调用时,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 函数不起作用的主要内容,如果未能解决你的问题,请参考以下文章

C# 调用 ListView 不起作用(后台线程)

如何使用 p/invoke 终止从 C# 调用的 C++ 函数

XSLT 2.0 中的尾递归函数不起作用

从后面的 C# 代码调用存储过程时插入语句不起作用

discord.py 2.0 url 作为函数不起作用

linux 平台上 C# 中的自定义 posix 信号不起作用