OSDN Git Service

ART: Change ThreadPool::Wait behavior
authorAndreas Gampe <agampe@google.com>
Wed, 16 Nov 2016 21:58:05 +0000 (13:58 -0800)
committerAndreas Gampe <agampe@google.com>
Thu, 17 Nov 2016 16:33:16 +0000 (08:33 -0800)
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

runtime/thread_pool.cc
runtime/thread_pool.h
runtime/thread_pool_test.cc

index b14f340..65fd999 100644 (file)
@@ -177,7 +177,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);
     }
@@ -200,7 +200,7 @@ Task* ThreadPool::TryGetTask(Thread* self) {
 }
 
 Task* ThreadPool::TryGetTaskLocked() {
-  if (started_ && !tasks_.empty()) {
+  if (HasOutstandingTasks()) {
     Task* task = tasks_.front();
     tasks_.pop_front();
     return task;
@@ -218,7 +218,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 {
index b6c6f02..2ff33a6 100644 (file)
@@ -100,7 +100,8 @@ class ThreadPool {
   ThreadPool(const char* name, size_t num_threads);
   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.
   void Wait(Thread* self, bool do_work, bool may_hold_locks) REQUIRES(!task_queue_lock_);
 
   size_t GetTaskCount(Thread* self) REQUIRES(!task_queue_lock_);
@@ -130,6 +131,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_);
index d5f17d1..2ae2ecf 100644 (file)
@@ -98,6 +98,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)