执行线程

时间:2016-01-12 16:41:56

标签: c++builder firemonkey c++builder-xe8

我有一个带有进度条的表单和一个将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;
}

1 个答案:

答案 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