mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-09 10:43:19 -05:00
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".
This commit is contained in:
parent
5e0c221356
commit
de9de2de36
1 changed files with 37 additions and 3 deletions
|
@ -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");
|
||||||
|
if (workQueue) {
|
||||||
|
LogPrint("http", "Waiting for HTTP worker threads to exit\n");
|
||||||
|
workQueue->WaitExit();
|
||||||
delete workQueue;
|
delete workQueue;
|
||||||
|
}
|
||||||
if (eventHTTP) {
|
if (eventHTTP) {
|
||||||
evhttp_free(eventHTTP);
|
evhttp_free(eventHTTP);
|
||||||
eventHTTP = 0;
|
eventHTTP = 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue