Added option to close a queue and wait for queued up operations to finish,
rather than just closing a queue and immediately cancelling all operations.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
static std::atomic<size_t> workerCounter(0);
|
||||
|
||||
AsyncRPCQueue::AsyncRPCQueue() : closed_(false) {
|
||||
AsyncRPCQueue::AsyncRPCQueue() : closed_(false), finish_(false) {
|
||||
}
|
||||
|
||||
AsyncRPCQueue::~AsyncRPCQueue() {
|
||||
@@ -18,15 +18,20 @@ AsyncRPCQueue::~AsyncRPCQueue() {
|
||||
*/
|
||||
void AsyncRPCQueue::run(size_t workerId) {
|
||||
|
||||
while (!isClosed()) {
|
||||
while (true) {
|
||||
AsyncRPCOperationId key;
|
||||
std::shared_ptr<AsyncRPCOperation> operation;
|
||||
{
|
||||
std::unique_lock< std::mutex > guard(lock_);
|
||||
while (operation_id_queue_.empty() && !isClosed()) {
|
||||
while (operation_id_queue_.empty() && !isClosed() && !isFinishing()) {
|
||||
this->condition_.wait(guard);
|
||||
}
|
||||
|
||||
// Exit if the queue is empty and we are finishing up
|
||||
if ( isFinishing() && operation_id_queue_.empty() ) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Exit if the queue is closing.
|
||||
if (isClosed()) {
|
||||
break;
|
||||
@@ -66,8 +71,8 @@ void AsyncRPCQueue::run(size_t workerId) {
|
||||
*/
|
||||
void AsyncRPCQueue::addOperation(const std::shared_ptr<AsyncRPCOperation> &ptrOperation) {
|
||||
|
||||
// Don't add if queue is closed
|
||||
if (isClosed()) {
|
||||
// Don't add if queue is closed or finishing
|
||||
if (isClosed() || isFinishing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -110,17 +115,31 @@ std::shared_ptr<AsyncRPCOperation> AsyncRPCQueue::popOperationForId(AsyncRPCOper
|
||||
* Return true if the queue is closed to new operations.
|
||||
*/
|
||||
bool AsyncRPCQueue::isClosed() const {
|
||||
return closed_;
|
||||
return closed_.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the queue and cancel all existing operations
|
||||
*/
|
||||
void AsyncRPCQueue::close() {
|
||||
this->closed_ = true;
|
||||
closed_.store(true);
|
||||
cancelAllOperations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the queue is finishing up
|
||||
*/
|
||||
bool AsyncRPCQueue::isFinishing() const {
|
||||
return finish_.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the queue but finish existing operations. Do not accept new operations.
|
||||
*/
|
||||
void AsyncRPCQueue::finish() {
|
||||
finish_.store(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call cancel() on all operations
|
||||
*/
|
||||
@@ -171,9 +190,28 @@ std::vector<AsyncRPCOperationId> AsyncRPCQueue::getAllOperationIds() const {
|
||||
* Calling thread will close and wait for worker threads to join.
|
||||
*/
|
||||
void AsyncRPCQueue::closeAndWait() {
|
||||
if (!this->closed_) {
|
||||
close();
|
||||
close();
|
||||
wait_for_worker_threads();
|
||||
}
|
||||
|
||||
/**
|
||||
* Block current thread until all workers have finished their tasks.
|
||||
*/
|
||||
void AsyncRPCQueue::finishAndWait() {
|
||||
finish();
|
||||
wait_for_worker_threads();
|
||||
}
|
||||
|
||||
/**
|
||||
* Block current thread until all operations are finished or the queue has closed.
|
||||
*/
|
||||
void AsyncRPCQueue::wait_for_worker_threads() {
|
||||
// Notify any workers who are waiting, so they see the updated queue state
|
||||
{
|
||||
std::unique_lock< std::mutex > guard(lock_);
|
||||
this->condition_.notify_all();
|
||||
}
|
||||
|
||||
for (std::thread & t : this->workers_) {
|
||||
if (t.joinable()) {
|
||||
t.join();
|
||||
|
||||
Reference in New Issue
Block a user