ThreadPool: On exception, interrupt the other worker threads
This commit is contained in:
		
							parent
							
								
									6a888ec29a
								
							
						
					
					
						commit
						b7376edf06
					
				
					 4 changed files with 14 additions and 7 deletions
				
			
		|  | @ -21,7 +21,7 @@ ThreadPool::~ThreadPool() | ||||||
|     std::vector<std::thread> workers; |     std::vector<std::thread> workers; | ||||||
|     { |     { | ||||||
|         auto state(state_.lock()); |         auto state(state_.lock()); | ||||||
|         state->quit = true; |         quit = true; | ||||||
|         std::swap(workers, state->workers); |         std::swap(workers, state->workers); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -36,7 +36,7 @@ ThreadPool::~ThreadPool() | ||||||
| void ThreadPool::enqueue(const work_t & t) | void ThreadPool::enqueue(const work_t & t) | ||||||
| { | { | ||||||
|     auto state(state_.lock()); |     auto state(state_.lock()); | ||||||
|     if (state->quit) |     if (quit) | ||||||
|         throw ThreadPoolShutDown("cannot enqueue a work item while the thread pool is shutting down"); |         throw ThreadPoolShutDown("cannot enqueue a work item while the thread pool is shutting down"); | ||||||
|     state->left.push(t); |     state->left.push(t); | ||||||
|     if (state->left.size() > state->workers.size() && state->workers.size() < maxThreads) |     if (state->left.size() > state->workers.size() && state->workers.size() < maxThreads) | ||||||
|  | @ -63,6 +63,8 @@ void ThreadPool::process() | ||||||
| 
 | 
 | ||||||
| void ThreadPool::workerEntry() | void ThreadPool::workerEntry() | ||||||
| { | { | ||||||
|  |     interruptCheck = [&]() { return (bool) quit; }; | ||||||
|  | 
 | ||||||
|     bool didWork = false; |     bool didWork = false; | ||||||
|     std::exception_ptr exc; |     std::exception_ptr exc; | ||||||
| 
 | 
 | ||||||
|  | @ -80,7 +82,7 @@ void ThreadPool::workerEntry() | ||||||
|                     if (!state->exception) { |                     if (!state->exception) { | ||||||
|                         state->exception = exc; |                         state->exception = exc; | ||||||
|                         // Tell the other workers to quit.
 |                         // Tell the other workers to quit.
 | ||||||
|                         state->quit = true; |                         quit = true; | ||||||
|                         work.notify_all(); |                         work.notify_all(); | ||||||
|                     } else { |                     } else { | ||||||
|                         /* Print the exception, since we can't
 |                         /* Print the exception, since we can't
 | ||||||
|  | @ -100,7 +102,7 @@ void ThreadPool::workerEntry() | ||||||
|             /* Wait until a work item is available or another thread
 |             /* Wait until a work item is available or another thread
 | ||||||
|                had an exception or we're asked to quit. */ |                had an exception or we're asked to quit. */ | ||||||
|             while (true) { |             while (true) { | ||||||
|                 if (state->quit) { |                 if (quit) { | ||||||
|                     if (!state->active) |                     if (!state->active) | ||||||
|                         done.notify_one(); |                         done.notify_one(); | ||||||
|                     return; |                     return; | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <map> | #include <map> | ||||||
|  | #include <atomic> | ||||||
| 
 | 
 | ||||||
| namespace nix { | namespace nix { | ||||||
| 
 | 
 | ||||||
|  | @ -47,9 +48,10 @@ private: | ||||||
|         size_t active = 0; |         size_t active = 0; | ||||||
|         std::exception_ptr exception; |         std::exception_ptr exception; | ||||||
|         std::vector<std::thread> workers; |         std::vector<std::thread> workers; | ||||||
|         bool quit = false; |  | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     std::atomic_bool quit{false}; | ||||||
|  | 
 | ||||||
|     Sync<State> state_; |     Sync<State> state_; | ||||||
| 
 | 
 | ||||||
|     std::condition_variable work, done; |     std::condition_variable work, done; | ||||||
|  |  | ||||||
|  | @ -1002,6 +1002,7 @@ void closeOnExec(int fd) | ||||||
| bool _isInterrupted = false; | bool _isInterrupted = false; | ||||||
| 
 | 
 | ||||||
| static thread_local bool interruptThrown = false; | static thread_local bool interruptThrown = false; | ||||||
|  | thread_local std::function<bool()> interruptCheck; | ||||||
| 
 | 
 | ||||||
| void setInterruptThrown() | void setInterruptThrown() | ||||||
| { | { | ||||||
|  | @ -1020,7 +1021,6 @@ void _interrupted() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| //////////////////////////////////////////////////////////////////////
 | //////////////////////////////////////////////////////////////////////
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -273,13 +273,16 @@ void closeOnExec(int fd); | ||||||
| 
 | 
 | ||||||
| extern bool _isInterrupted; | extern bool _isInterrupted; | ||||||
| 
 | 
 | ||||||
|  | extern thread_local std::function<bool()> interruptCheck; | ||||||
|  | 
 | ||||||
| void setInterruptThrown(); | void setInterruptThrown(); | ||||||
| 
 | 
 | ||||||
| void _interrupted(); | void _interrupted(); | ||||||
| 
 | 
 | ||||||
| void inline checkInterrupt() | void inline checkInterrupt() | ||||||
| { | { | ||||||
|     if (_isInterrupted) _interrupted(); |     if (_isInterrupted || (interruptCheck && interruptCheck())) | ||||||
|  |         _interrupted(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MakeError(Interrupted, BaseError) | MakeError(Interrupted, BaseError) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue