Rox*_*Rox 3 c# multithreading backgroundworker
我们有一个 C# 应用程序,它连接到 FTP 服务器、下载一些文件、断开连接,并在一段时间后(由用户通过 UI 选择)重新连接并重复该过程。我们使用BackgroundWorker 实现了这一点,但我们注意到,运行较长时间后,程序停止在UI 和日志文件中记录其操作。那时,没有文件可供它下载,因此我们上传了一些文件,它恢复了活动,就好像什么也没发生一样。
问题是普通用户无法知道程序仍在运行,因此我们决定使用我们自己的线程来实现它。我们做了一个更简单的程序,以排除任何其他问题,这个程序只连接到 FTP 并断开连接。它像BackgroundWorker 一样停止显示消息(2 小时后一次,22 小时后一次,没有我们能找到的任何模式,并且在一台没有执行任何其他操作的计算机上)。
DoFTPWork += new DoFTPWorkDelegate(WriteFTPMessage);
FTPWorkThread = new Thread(new ParameterizedThreadStart(Process));
//seData is the FTP login info
FTPWorkThread.Start(seData);
Run Code Online (Sandbox Code Playgroud)
FTP方法是:
private void Process(object seData1)
{
seData = (SEData)seData1;
while (!stopped)
{
try
{
ftp = null;
ftp = new FTP_Client();
if (ftp.IsConnected)
{
logMessages += DateTime.Now + "\t" + "info" + "\t" + "Ftp disconnected from " + seData.host + "\r\n";
ftp.Disconnect();
}
ftp.Connect(seData.host, 21);
ftp.Authenticate(seData.userName, seData.password);
logMessages += DateTime.Now + "\t" + "info" + "\t" + "Ftp connected to " + seData.host + "\r\n";
error = false;
logMessages += DateTime.Now + "\t" + "info" + "\t" + "Trying to reconnect in 5 seconds\r\n";
System.Threading.Thread.Sleep(5000);
SlaveEventArgs ev = new SlaveEventArgs();
ev.Message = logMessages;
txtLog.Invoke(DoFTPWork, ev);
System.Threading.Thread.Sleep(200);
logMessages = "";
}
catch (Exception ex)
{
logMessages = "";
if (ftp.IsConnected)
{
ftp.Disconnect();
}
ftp.Dispose();
logMessages += DateTime.Now + "\t" + "ERR" + "\t" + ex.Message + "\r\n";
logMessages += DateTime.Now + "\t" + "info" + "\t" + "Trying to reconnect in 5 seconds\r\n";
SlaveEventArgs ev = new SlaveEventArgs();
ev.Message = logMessages;
txtLog.Invoke(DoFTPWork, ev);
System.Threading.Thread.Sleep(5 * 1000);
error = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
WriteFTPMessage 在文本框中显示消息,并在写入 .txt 文件的原始程序中显示消息。
如果我理解正确的话,这个while(!stopped)循环是运行几个小时的循环?如果是这种情况,您在哪里终止 ftp 连接(如果有的话)?在您发布的代码中关闭它的唯一一次是抛出异常,否则您只需取消引用该对象并创建一个新的对象,这是一个非常严重的资源泄漏,如果不是导致问题的话,至少会导致问题。
而且 ftp 似乎是全局可访问的。您是否使用不同的线程在任何地方访问它?对象线程安全吗?
编辑:
我在这里看到的最大问题是设计。并不是说我想攻击你或其他什么东西,而是你混合了各种各样的行动。线程、日志记录和 ftp 访问代码都在同一个函数中。
我的建议是重组你的程序。创建一个与以下类似的方法:
// Called by thread
void MyThreadOperation()
{
while(!stopped)
{
// This is poor design in terms of performance.
// Consider using a ResetEvent instead.
Thread.Sleep(5000);
try
{
doFTPDownload();
}
catch(Exception ex)
{
logMessage(ex.ToString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
doFTPDownload()应该是独立的。FTP 对象应在调用时在函数内创建并打开,并在完成之前将其关闭。logMessage()同样的概念也应该适用。我还建议使用数据库而不是文件来存储日志消息,以便锁定问题不会使问题变得复杂。
我知道这不是一个答案,因为您可能仍然会遇到问题,因为我无法确定可能的原因是什么。不过,我相信通过一些设计重组,您将能够更好地找到问题的根源。
| 归档时间: |
|
| 查看次数: |
2820 次 |
| 最近记录: |