You need to sign in or sign up before continuing.
simple_thread.h 7 KB
Newer Older
gejun's avatar
gejun committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// WARNING: You should probably be using Thread (thread.h) instead.  Thread is
//          Chrome's message-loop based Thread abstraction, and if you are a
//          thread running in the browser, there will likely be assumptions
//          that your thread will have an associated message loop.
//
// This is a simple thread interface that backs to a native operating system
// thread.  You should use this only when you want a thread that does not have
// an associated MessageLoop.  Unittesting is the best example of this.
//
// The simplest interface to use is DelegateSimpleThread, which will create
// a new thread, and execute the Delegate's virtual Run() in this new thread
// until it has completed, exiting the thread.
//
// NOTE: You *MUST* call Join on the thread to clean up the underlying thread
// resources.  You are also responsible for destructing the SimpleThread object.
// It is invalid to destroy a SimpleThread while it is running, or without
// Start() having been called (and a thread never created).  The Delegate
// object should live as long as a DelegateSimpleThread.
//
// Thread Safety: A SimpleThread is not completely thread safe.  It is safe to
// access it from the creating thread or from the newly created thread.  This
// implies that the creator thread should be the thread that calls Join.
//
// Example:
//   class MyThreadRunner : public DelegateSimpleThread::Delegate { ... };
//   MyThreadRunner runner;
//   DelegateSimpleThread thread(&runner, "good_name_here");
//   thread.Start();
//   // Start will return after the Thread has been successfully started and
//   // initialized.  The newly created thread will invoke runner->Run(), and
//   // run until it returns.
//   thread.Join();  // Wait until the thread has exited.  You *MUST* Join!
//   // The SimpleThread object is still valid, however you may not call Join
//   // or Start again.

40 41
#ifndef BUTIL_THREADING_SIMPLE_THREAD_H_
#define BUTIL_THREADING_SIMPLE_THREAD_H_
gejun's avatar
gejun committed
42 43 44 45 46

#include <string>
#include <queue>
#include <vector>

47 48 49 50 51 52
#include "butil/base_export.h"
#include "butil/basictypes.h"
#include "butil/compiler_specific.h"
#include "butil/threading/platform_thread.h"
#include "butil/synchronization/lock.h"
#include "butil/synchronization/waitable_event.h"
gejun's avatar
gejun committed
53

54
namespace butil {
gejun's avatar
gejun committed
55 56 57

// This is the base SimpleThread.  You can derive from it and implement the
// virtual Run method, or you can use the DelegateSimpleThread interface.
58
class BUTIL_EXPORT SimpleThread : public PlatformThread::Delegate {
gejun's avatar
gejun committed
59
 public:
60
  class BUTIL_EXPORT Options {
gejun's avatar
gejun committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
   public:
    Options() : stack_size_(0) { }
    ~Options() { }

    // We use the standard compiler-supplied copy constructor.

    // A custom stack size, or 0 for the system default.
    void set_stack_size(size_t size) { stack_size_ = size; }
    size_t stack_size() const { return stack_size_; }
   private:
    size_t stack_size_;
  };

  // Create a SimpleThread.  |options| should be used to manage any specific
  // configuration involving the thread creation and management.
  // Every thread has a name, in the form of |name_prefix|/TID, for example
  // "my_thread/321".  The thread will not be created until Start() is called.
  explicit SimpleThread(const std::string& name_prefix);
  SimpleThread(const std::string& name_prefix, const Options& options);

  virtual ~SimpleThread();

  virtual void Start();
  virtual void Join();

  // Subclasses should override the Run method.
  virtual void Run() = 0;

  // Return the thread name prefix, or "unnamed" if none was supplied.
  std::string name_prefix() { return name_prefix_; }

  // Return the completed name including TID, only valid after Start().
  std::string name() { return name_; }

  // Return the thread id, only valid after Start().
  PlatformThreadId tid() { return tid_; }

  // Return True if Start() has ever been called.
  bool HasBeenStarted();

  // Return True if Join() has evern been called.
  bool HasBeenJoined() { return joined_; }

  // Overridden from PlatformThread::Delegate:
  virtual void ThreadMain() OVERRIDE;

  // Only set priorities with a careful understanding of the consequences.
  // This is meant for very limited use cases.
  void SetThreadPriority(ThreadPriority priority) {
    PlatformThread::SetThreadPriority(thread_, priority);
  }

 private:
  const std::string name_prefix_;
  std::string name_;
  const Options options_;
  PlatformThreadHandle thread_;  // PlatformThread handle, invalid after Join!
  WaitableEvent event_;          // Signaled if Start() was ever called.
  PlatformThreadId tid_;         // The backing thread's id.
  bool joined_;                  // True if Join has been called.
};

123
class BUTIL_EXPORT DelegateSimpleThread : public SimpleThread {
gejun's avatar
gejun committed
124
 public:
125
  class BUTIL_EXPORT Delegate {
gejun's avatar
gejun committed
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
   public:
    Delegate() { }
    virtual ~Delegate() { }
    virtual void Run() = 0;
  };

  DelegateSimpleThread(Delegate* delegate,
                       const std::string& name_prefix);
  DelegateSimpleThread(Delegate* delegate,
                       const std::string& name_prefix,
                       const Options& options);

  virtual ~DelegateSimpleThread();
  virtual void Run() OVERRIDE;
 private:
  Delegate* delegate_;
};

// DelegateSimpleThreadPool allows you to start up a fixed number of threads,
// and then add jobs which will be dispatched to the threads.  This is
// convenient when you have a lot of small work that you want done
// multi-threaded, but don't want to spawn a thread for each small bit of work.
//
// You just call AddWork() to add a delegate to the list of work to be done.
// JoinAll() will make sure that all outstanding work is processed, and wait
// for everything to finish.  You can reuse a pool, so you can call Start()
// again after you've called JoinAll().
153
class BUTIL_EXPORT DelegateSimpleThreadPool
gejun's avatar
gejun committed
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
    : public DelegateSimpleThread::Delegate {
 public:
  typedef DelegateSimpleThread::Delegate Delegate;

  DelegateSimpleThreadPool(const std::string& name_prefix, int num_threads);
  virtual ~DelegateSimpleThreadPool();

  // Start up all of the underlying threads, and start processing work if we
  // have any.
  void Start();

  // Make sure all outstanding work is finished, and wait for and destroy all
  // of the underlying threads in the pool.
  void JoinAll();

  // It is safe to AddWork() any time, before or after Start().
  // Delegate* should always be a valid pointer, NULL is reserved internally.
  void AddWork(Delegate* work, int repeat_count);
  void AddWork(Delegate* work) {
    AddWork(work, 1);
  }

  // We implement the Delegate interface, for running our internal threads.
  virtual void Run() OVERRIDE;

 private:
  const std::string name_prefix_;
  int num_threads_;
  std::vector<DelegateSimpleThread*> threads_;
  std::queue<Delegate*> delegates_;
184
  butil::Lock lock_;            // Locks delegates_
gejun's avatar
gejun committed
185 186 187
  WaitableEvent dry_;    // Not signaled when there is no work to do.
};

188
}  // namespace butil
gejun's avatar
gejun committed
189

190
#endif  // BUTIL_THREADING_SIMPLE_THREAD_H_