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.