Browse Source

http: Wait for worker threads to exit

Add a WaitExit() call to http's WorkQueue to make it delete the work
queue only when all worker threads stopped.

This fixes a problem that was reproducable by pressing Ctrl-C during
AppInit2:
```
/usr/include/boost/thread/pthread/condition_variable_fwd.hpp:81: boost::condition_variable::~condition_variable(): Assertion `!ret' failed.
/usr/include/boost/thread/pthread/mutex.hpp:108: boost::mutex::~mutex(): Assertion `!posix::pthread_mutex_destroy(&m)' failed.
```

I was assuming that `threadGroup->join_all();` would always have been
called when entering the Shutdown(). However this is not the case in
bitcoind's AppInit2-non-zero-exit case "was left out intentionally
here".
0.13
Wladimir J. van der Laan 9 years ago
parent
commit
de9de2de36
  1. 40
      src/httpserver.cpp

40
src/httpserver.cpp

@ -72,13 +72,35 @@ private:
std::deque<WorkItem*> queue; std::deque<WorkItem*> queue;
bool running; bool running;
size_t maxDepth; size_t maxDepth;
int numThreads;
/** RAII object to keep track of number of running worker threads */
class ThreadCounter
{
public:
WorkQueue &wq;
ThreadCounter(WorkQueue &w): wq(w)
{
boost::lock_guard<boost::mutex> lock(wq.cs);
wq.numThreads += 1;
}
~ThreadCounter()
{
boost::lock_guard<boost::mutex> lock(wq.cs);
wq.numThreads -= 1;
wq.cond.notify_all();
}
};
public: public:
WorkQueue(size_t maxDepth) : running(true), WorkQueue(size_t maxDepth) : running(true),
maxDepth(maxDepth) maxDepth(maxDepth),
numThreads(0)
{ {
} }
/* Precondition: worker threads have all stopped */ /*( Precondition: worker threads have all stopped
* (call WaitExit)
*/
~WorkQueue() ~WorkQueue()
{ {
while (!queue.empty()) { while (!queue.empty()) {
@ -100,6 +122,7 @@ public:
/** Thread function */ /** Thread function */
void Run() void Run()
{ {
ThreadCounter count(*this);
while (running) { while (running) {
WorkItem* i = 0; WorkItem* i = 0;
{ {
@ -122,6 +145,13 @@ public:
running = false; running = false;
cond.notify_all(); cond.notify_all();
} }
/** Wait for worker threads to exit */
void WaitExit()
{
boost::unique_lock<boost::mutex> lock(cs);
while (numThreads > 0)
cond.wait(lock);
}
/** Return current depth of queue */ /** Return current depth of queue */
size_t Depth() size_t Depth()
@ -434,7 +464,11 @@ void InterruptHTTPServer()
void StopHTTPServer() void StopHTTPServer()
{ {
LogPrint("http", "Stopping HTTP server\n"); LogPrint("http", "Stopping HTTP server\n");
delete workQueue; if (workQueue) {
LogPrint("http", "Waiting for HTTP worker threads to exit\n");
workQueue->WaitExit();
delete workQueue;
}
if (eventHTTP) { if (eventHTTP) {
evhttp_free(eventHTTP); evhttp_free(eventHTTP);
eventHTTP = 0; eventHTTP = 0;

Loading…
Cancel
Save