dimanche 27 décembre 2015

How to invoke a method in a separate thread and use the return status

I have a class with one method which sends a POST request to a host with file(s) attached (and delete the file(s) once the request has been made). This is the barebone code:

using namespace Poco;
using namespace Poco::Net;

FileUploader::FileUploader(std::string aPathToFile): fPathToFile(aPathToFile)
{
}

void FileUploader::uploadFileInSeparateThread()
{
    std::thread([&](){
        this->uploadFile();
    }).detach();
}

bool FileUploader::uploadFile()
{
    try {
        const Context::Ptr context(new Context(Context::CLIENT_USE, "", "", "~/Desktop/root.pem",Context::VERIFY_ONCE));
        Poco::Net::HTTPSClientSession httpsSession(HOST, 443,context);

        HTTPRequest request(HTTPRequest::HTTP_POST, "/path/to/service?key=<name_of_file_to_be_uploaded>", HTTPMessage::HTTP_1_1);
        request.setContentType("application/x-www-form-urlencoded");
        request.setKeepAlive(true);
        HTMLForm form;
        form.setEncoding(HTMLForm::ENCODING_MULTIPART);
        form.addPart("file", new FilePartSource(fPathToFile));
        form.prepareSubmit(request);

        httpsSession.setKeepAlive(true);
        httpsSession.setTimeout(Poco::Timespan(20, 0));
        form.write(httpsSession.sendRequest(request));

        Poco::Net::HTTPResponse res;
        std::istream &is = httpsSession.receiveResponse(res);
        Poco::StreamCopier::copyStream(is, std::cout);
        qDebug() << "Message: " << is.rdbuf() << endl;
        return true;
    }
    catch (Exception &ex)
    {
        qDebug() << "Damn: " << ex.displayText().c_str() << endl;
        return false;
    }
}

If I invoke the class like this:

FileUploader uploader(tempfilePath.toStdString());
uploader.uploadFile();

It works fine, however, while the request is ongoing, UI is blocked. So I decided to mutithread it and created a new method uploadFileInSeparataeThread. Then I just call

FileUploader *uploader = new FileUploader(tempfilePath.toStdString());
uploader->uploadFileInSeparataeThread();

This works fine, but problem is, the memory occupied by uploader is never deleted. So I made it a unique pointer instead:

std::unique_ptr<FileUploader> uploader(new FileUploader(tempfilePath.toStdString()));
uploader->uploadFileInSeparataeThread();

This doesn't work, I get a Damn, file does not exist error, which happens when the file I am trying to upload in the form.addPart("file", new FilePartSource(fPathToFile)); part is missing. This is probably expected, unique pointer will go out of scope the moment the invoking method ends. So I tried this:

FileUploader uploader(tempfilePath.toStdString());
std::thread thread([&] (FileUploader * newUploader) { newUploader->uploadFile(); }, &uploader);
thread.join();

Now this works, but it is not multithreaded, UI is still blocked when the request is ongoing.

How do I make it properly multithreaded, and use the return value from uploadFile() to delete the temp file being uploaded once the POST request has been made successfully?

Aucun commentaire:

Enregistrer un commentaire