Home | History | Annotate | Download | only in threading
      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