简体   繁体   中英

Starting thread from Poco::HTTPServer

I've encountered a strange behavior starting a thread from Poco::HTTPServer

Here's what i've got:

class Worker : public Poco::Runnable {
public:
    Worker(std::string request): _request(request) {};
    void run();
    std::string GetResult();
private:
    std::string _request;
};

void Worker::run() {
    // do something with _request;
}

class RequestHandler : public HTTPRequestHandler {
public:
  virtual void handleRequest(HTTPServerRequest &req, HTTPServerResponse &resp) {

    std::string request(static_cast<stringstream const&>(stringstream() << req.stream().rdbuf()).str());

    Poco::Thread thread;
    Worker worker(request);

    std::string response = "";

    thread.start(worker);

    // parsing content of the request to detect if request is async or sync

    if(async) {
    // make dummy response 
        response = "your request queued";
    } else { // if sync
        thread.join();
        response = worker.GetResult();
    }
    ostream& out = resp.send();
    out << response;
    out.flush();
  }

private:
};

Now, if request is of sync type all ok, RequestHandler waits for thread's join and then responses with worker's result, all ok. But if request is of async type i don't need to wait for thread join, i just need to send a dummy response while worker thread continues to process the request. The problem is segfault after several async requests. Like this:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff2e4c700 (LWP 13986)]
0x0000000000000000 in ?? ()
(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x00007ffff7a3f76e in Poco::ThreadImpl::runnableEntry (pThread=0x7ffff464e930) at /home/uzurik/libs/poco-PostgreSQL/Foundation/src/Thread_POSIX.cpp:436
#2  0x00007ffff66c26aa in start_thread (arg=0x7ffff2e4c700) at pthread_create.c:333
#3  0x00007ffff69dfeed in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

What i'm doing wrong?

The reason you get segfault is because the thread is not joined when async is true. Worker will be destroyed before thread and it's a matter of chance whether run() had completed at that time or not (remember, it runs in a separate thread of execution). Accessing state of a destroyed object leads to undefined behavior.

If you swap the declarations of Thread and Worker , Thread would be destroyed first, but what exactly happens (eventually a bad thing for sure) depends on whether Worker::run() has already started executing or not.

So, join (or some other form of syncing) is the only way to guarantee orderly execution and cleanup. In any other scenario, you are risking finding yourself in a member function of a destroyed Worker object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM