我有一个带有进度条的表单和一个将xml上传到服务器的按钮。 按下按钮时,会创建一个创建套接字的新线程,然后以块的形式将数据发送到服务器,同时更新进度条。 现在,当第二次按下上传按钮时,我得到访问冲突,而在调试器中,进度条对象的地址为NULL。 我无法弄清楚为什么进度条会被释放,所以如果有人有任何想法我将不胜感激。
P.S。目标操作系统是Windows PS2如果相同的代码在主线程上运行而没有使用线程,那么我似乎没有这个问题,即使我在线程中跳过整体进度条的使用它也被设置为null在第一次按下上传按钮后再次。
线程构造函数:
__fastcall UploadRouteThread::UploadRouteThread(bool CreateSuspended) : TThread(CreateSuspended)
{
this->OnTerminate = OnTerminateHandler;
ioHandlerStack = new TIdIOHandlerStack();
tcpClient = new TIdTCPClient();
tcpClient->ReadTimeout = -1;
tcpClient->UseNagle = true;
tcpClient->IOHandler = ioHandlerStack;
tcpClient->OnConnected = OnConnectedHandler;
}
OnTerminate处理程序:
void __fastcall UploadRouteThread::OnTerminateHandler(TObject *Sender)
{
TabbedwithNavigationForm->UploadButton->Text = "Upload";
TabbedwithNavigationForm->UploadButton->Enabled = false;
TabbedwithNavigationForm->ProgressBar->Visible = false;
tcpClient->DisconnectNotifyPeer();
ShowMessage("Data uploaded.");
delete ioHandlerStack;
delete tcpClient;
TabbedwithNavigationForm->OptionButton->Enabled = true;
TabbedwithNavigationForm->RetrieveRoutesButton->Enabled = true;
TabbedwithNavigationForm->TrackButton->Enabled = true;
TabbedwithNavigationForm->MediaButton->Enabled = true;
}
执行方法:
void __fastcall UploadRouteThread::Execute()
{
FreeOnTerminate = true;
tcpClient->Connect();
}
两个补充功能:
void __fastcall UploadRouteThread::SetHostPort(UnicodeString host, unsigned short port)
{
tcpClient->Host = host;
tcpClient->Port = port;
}
void __fastcall UploadRouteThread::SetXML(AnsiString xmlString)
{
this->xmlString = xmlString;
}
OnConnect处理程序:
void __fastcall UploadRouteThread::OnConnectedHandler(TObject *Sender)
{
NextPacketSize nps;
TIdBytes bytes;
int chunks;
int bytesLength;
nps.PacketID = BasicPacket::DATA_UPLOAD;
nps.size = xmlString.Length();
tcpClient->IOHandler->WriteDirect(RawToBytes(&nps, sizeof(nps)), sizeof(NextPacketSize));
bytes = RawToBytes(xmlString.c_str(), xmlString.Length());
bytesLength = bytes.get_length();
chunks = ceil(float(bytesLength) / 256.0);
int previousSizeSent(0);
for(int i = 1; i <= chunks; i++)
{
if(Terminated)
break;
int bytesToSend = 256;
TByteDynArray byteDynArray;
if((bytesToSend > bytesLength))
{
bytesToSend = bytesLength;
}
byteDynArray = bytes.CopyRange(previousSizeSent, bytesToSend);
tcpClient->IOHandler->WriteDirect(ToBytes(byteDynArray, byteDynArray.get_length(), 0),
byteDynArray.get_length());
sent = (float(i) / float(chunks)) * 100;
TThread::Synchronize(this, UpdateProgressBarInternal);
previousSizeSent += bytesToSend;
bytesLength -= bytesToSend;
}
}
进度条的Update方法:
void __fastcall UploadRouteThread::UpdateProgressBarInternal()
{
if(!TabbedwithNavigationForm->ProgressBar->Visible)
{
TabbedwithNavigationForm->ProgressBar->Visible = true;
TabbedwithNavigationForm->ProgressBar->Max = 100;
}
TabbedwithNavigationForm->ProgressBar->Value = sent;
}
答案 0 :(得分:1)
我在这段代码中看不到会导致ProgressBar指针变为final Task task = new Task();
task.put("description", description);
task.put("date", date);
task.put("time", time);
task.put("location", location);
task.saveInBackground();
group.add("tasks", task);
group.saveInBackground();
的任何内容。因此,无论是破坏内存,还是其他未显示的代码中的其他内容都是罪魁祸首。无论哪种方式,要解决此问题,您可以在IDE调试器中运行您的应用程序,并在第一次运行线程之前在ProgressBar变量上设置数据断点。如果某些内容更改了该指针的值,则会触发断点,您可以查看调用堆栈以了解发生的情况。
话虽如此,你的线程组织得不是很好。并且有一种更简单的方法来处理分块 - 让Indy为你做。它有一个NULL
事件,您可以将其用于ProgressBar更新。
尝试更像这样的事情:
OnWork