1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/threading/simple_thread.h" 6 7 #include "base/logging.h" 8 #include "base/threading/platform_thread.h" 9 #include "base/string_number_conversions.h" 10 11 namespace base { 12 13 SimpleThread::SimpleThread(const std::string& name_prefix) 14 : name_prefix_(name_prefix), name_(name_prefix), 15 thread_(), event_(true, false), tid_(0), joined_(false) { 16 } 17 18 SimpleThread::SimpleThread(const std::string& name_prefix, 19 const Options& options) 20 : name_prefix_(name_prefix), name_(name_prefix), options_(options), 21 thread_(), event_(true, false), tid_(0), joined_(false) { 22 } 23 24 SimpleThread::~SimpleThread() { 25 DCHECK(HasBeenStarted()) << "SimpleThread was never started."; 26 DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed."; 27 } 28 29 void SimpleThread::Start() { 30 DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times."; 31 bool success = PlatformThread::Create(options_.stack_size(), this, &thread_); 32 CHECK(success); 33 event_.Wait(); // Wait for the thread to complete initialization. 34 } 35 36 void SimpleThread::Join() { 37 DCHECK(HasBeenStarted()) << "Tried to Join a never-started thread."; 38 DCHECK(!HasBeenJoined()) << "Tried to Join a thread multiple times."; 39 PlatformThread::Join(thread_); 40 joined_ = true; 41 } 42 43 void SimpleThread::ThreadMain() { 44 tid_ = PlatformThread::CurrentId(); 45 // Construct our full name of the form "name_prefix_/TID". 46 name_.push_back('/'); 47 name_.append(IntToString(tid_)); 48 PlatformThread::SetName(name_.c_str()); 49 50 // We've initialized our new thread, signal that we're done to Start(). 51 event_.Signal(); 52 53 Run(); 54 } 55 56 DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate, 57 const std::string& name_prefix) 58 : SimpleThread(name_prefix), 59 delegate_(delegate) { 60 } 61 62 DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate, 63 const std::string& name_prefix, 64 const Options& options) 65 : SimpleThread(name_prefix, options), 66 delegate_(delegate) { 67 } 68 69 DelegateSimpleThread::~DelegateSimpleThread() { 70 } 71 72 void DelegateSimpleThread::Run() { 73 DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)"; 74 delegate_->Run(); 75 delegate_ = NULL; 76 } 77 78 DelegateSimpleThreadPool::DelegateSimpleThreadPool( 79 const std::string& name_prefix, 80 int num_threads) 81 : name_prefix_(name_prefix), 82 num_threads_(num_threads), 83 dry_(true, false) { 84 } 85 86 DelegateSimpleThreadPool::~DelegateSimpleThreadPool() { 87 DCHECK(threads_.empty()); 88 DCHECK(delegates_.empty()); 89 DCHECK(!dry_.IsSignaled()); 90 } 91 92 void DelegateSimpleThreadPool::Start() { 93 DCHECK(threads_.empty()) << "Start() called with outstanding threads."; 94 for (int i = 0; i < num_threads_; ++i) { 95 DelegateSimpleThread* thread = new DelegateSimpleThread(this, name_prefix_); 96 thread->Start(); 97 threads_.push_back(thread); 98 } 99 } 100 101 void DelegateSimpleThreadPool::JoinAll() { 102 DCHECK(!threads_.empty()) << "JoinAll() called with no outstanding threads."; 103 104 // Tell all our threads to quit their worker loop. 105 AddWork(NULL, num_threads_); 106 107 // Join and destroy all the worker threads. 108 for (int i = 0; i < num_threads_; ++i) { 109 threads_[i]->Join(); 110 delete threads_[i]; 111 } 112 threads_.clear(); 113 DCHECK(delegates_.empty()); 114 } 115 116 void DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) { 117 AutoLock locked(lock_); 118 for (int i = 0; i < repeat_count; ++i) 119 delegates_.push(delegate); 120 // If we were empty, signal that we have work now. 121 if (!dry_.IsSignaled()) 122 dry_.Signal(); 123 } 124 125 void DelegateSimpleThreadPool::Run() { 126 Delegate* work = NULL; 127 128 while (true) { 129 dry_.Wait(); 130 { 131 AutoLock locked(lock_); 132 if (!dry_.IsSignaled()) 133 continue; 134 135 DCHECK(!delegates_.empty()); 136 work = delegates_.front(); 137 delegates_.pop(); 138 139 // Signal to any other threads that we're currently out of work. 140 if (delegates_.empty()) 141 dry_.Reset(); 142 } 143 144 // A NULL delegate pointer signals us to quit. 145 if (!work) 146 break; 147 148 work->Run(); 149 } 150 } 151 152 } // namespace base 153