Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

Commit

Permalink
ART: Change ThreadPool::Wait behavior
Browse files Browse the repository at this point in the history
When a pool is in the stopped state, Wait() will not wait for all
tasks to complete.

Bug: 31385354
Test: m test-art-host-gtest-thread_pool_test
Change-Id: Id0144b685ee2fddf1a1c2c2ca334251130121033
  • Loading branch information
agampe authored and rovo89 committed Oct 8, 2017
1 parent e3c8d25 commit 7741e0b
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 4 deletions.
6 changes: 3 additions & 3 deletions runtime/thread_pool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ Task* ThreadPool::GetTask(Thread* self) {
}

++waiting_count_;
if (waiting_count_ == GetThreadCount() && tasks_.empty()) {
if (waiting_count_ == GetThreadCount() && !HasOutstandingTasks()) {
// We may be done, lets broadcast to the completion condition.
completion_condition_.Broadcast(self);
}
Expand All @@ -206,7 +206,7 @@ Task* ThreadPool::TryGetTask(Thread* self) {
}

Task* ThreadPool::TryGetTaskLocked() {
if (started_ && !tasks_.empty()) {
if (HasOutstandingTasks()) {
Task* task = tasks_.front();
tasks_.pop_front();
return task;
Expand All @@ -225,7 +225,7 @@ void ThreadPool::Wait(Thread* self, bool do_work, bool may_hold_locks) {
}
// Wait until each thread is waiting and the task list is empty.
MutexLock mu(self, task_queue_lock_);
while (!shutting_down_ && (waiting_count_ != GetThreadCount() || !tasks_.empty())) {
while (!shutting_down_ && (waiting_count_ != GetThreadCount() || HasOutstandingTasks())) {
if (!may_hold_locks) {
completion_condition_.Wait(self);
} else {
Expand Down
7 changes: 6 additions & 1 deletion runtime/thread_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ class ThreadPool {
ThreadPool(const char* name, size_t num_threads, bool create_peers = false);
virtual ~ThreadPool();

// Wait for all tasks currently on queue to get completed.
// Wait for all tasks currently on queue to get completed. If the pool has been stopped, only
// wait till all already running tasks are done.
// When the pool was created with peers for workers, do_work must not be true (see ThreadPool()).
void Wait(Thread* self, bool do_work, bool may_hold_locks) REQUIRES(!task_queue_lock_);

Expand Down Expand Up @@ -137,6 +138,10 @@ class ThreadPool {
return shutting_down_;
}

bool HasOutstandingTasks() const REQUIRES(task_queue_lock_) {
return started_ && !tasks_.empty();
}

const std::string name_;
Mutex task_queue_lock_;
ConditionVariable task_queue_condition_ GUARDED_BY(task_queue_lock_);
Expand Down
18 changes: 18 additions & 0 deletions runtime/thread_pool_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,24 @@ TEST_F(ThreadPoolTest, StopStart) {
thread_pool.Wait(self, false, false);
}

TEST_F(ThreadPoolTest, StopWait) {
Thread* self = Thread::Current();
ThreadPool thread_pool("Thread pool test thread pool", num_threads);

AtomicInteger count(0);
static const int32_t num_tasks = num_threads * 100;
for (int32_t i = 0; i < num_tasks; ++i) {
thread_pool.AddTask(self, new CountTask(&count));
}

// Signal the threads to start processing tasks.
thread_pool.StartWorkers(self);
usleep(200);
thread_pool.StopWorkers(self);

thread_pool.Wait(self, false, false); // We should not deadlock here.
}

class TreeTask : public Task {
public:
TreeTask(ThreadPool* const thread_pool, AtomicInteger* count, int depth)
Expand Down

0 comments on commit 7741e0b

Please sign in to comment.