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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 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 123 124 125 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 153 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 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
|
// Copyright (c) 2012 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.
#ifndef BASE_THREADING_THREAD_H_
#define BASE_THREADING_THREAD_H_
#include <string>
#include "base/base_export.h"
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/threading/platform_thread.h"
namespace base {
class MessagePump;
// A simple thread abstraction that establishes a MessageLoop on a new thread.
// The consumer uses the MessageLoop of the thread to cause code to execute on
// the thread. When this object is destroyed the thread is terminated. All
// pending tasks queued on the thread's message loop will run to completion
// before the thread is terminated.
//
// WARNING! SUBCLASSES MUST CALL Stop() IN THEIR DESTRUCTORS! See ~Thread().
//
// After the thread is stopped, the destruction sequence is:
//
// (1) Thread::CleanUp()
// (2) MessageLoop::~MessageLoop
// (3.b) MessageLoop::DestructionObserver::WillDestroyCurrentMessageLoop
class BASE_EXPORT Thread : PlatformThread::Delegate {
public:
struct BASE_EXPORT Options {
typedef Callback<scoped_ptr<MessagePump>()> MessagePumpFactory;
Options();
Options(MessageLoop::Type type, size_t size);
~Options();
// Specifies the type of message loop that will be allocated on the thread.
// This is ignored if message_pump_factory.is_null() is false.
MessageLoop::Type message_loop_type;
// Used to create the MessagePump for the MessageLoop. The callback is Run()
// on the thread. If message_pump_factory.is_null(), then a MessagePump
// appropriate for |message_loop_type| is created. Setting this forces the
// MessageLoop::Type to TYPE_CUSTOM.
MessagePumpFactory message_pump_factory;
// Specifies the maximum stack size that the thread is allowed to use.
// This does not necessarily correspond to the thread's initial stack size.
// A value of 0 indicates that the default maximum should be used.
size_t stack_size;
};
// Constructor.
// name is a display string to identify the thread.
explicit Thread(const std::string& name);
// Destroys the thread, stopping it if necessary.
//
// NOTE: ALL SUBCLASSES OF Thread MUST CALL Stop() IN THEIR DESTRUCTORS (or
// guarantee Stop() is explicitly called before the subclass is destroyed).
// This is required to avoid a data race between the destructor modifying the
// vtable, and the thread's ThreadMain calling the virtual method Run(). It
// also ensures that the CleanUp() virtual method is called on the subclass
// before it is destructed.
virtual ~Thread();
#if defined(OS_WIN)
// Causes the thread to initialize COM. This must be called before calling
// Start() or StartWithOptions(). If |use_mta| is false, the thread is also
// started with a TYPE_UI message loop. It is an error to call
// init_com_with_mta(false) and then StartWithOptions() with any message loop
// type other than TYPE_UI.
void init_com_with_mta(bool use_mta) {
DCHECK(!started_);
com_status_ = use_mta ? MTA : STA;
}
#endif
// Starts the thread. Returns true if the thread was successfully started;
// otherwise, returns false. Upon successful return, the message_loop()
// getter will return non-null.
//
// Note: This function can't be called on Windows with the loader lock held;
// i.e. during a DllMain, global object construction or destruction, atexit()
// callback.
bool Start();
// Starts the thread. Behaves exactly like Start in addition to allow to
// override the default options.
//
// Note: This function can't be called on Windows with the loader lock held;
// i.e. during a DllMain, global object construction or destruction, atexit()
// callback.
bool StartWithOptions(const Options& options);
// Signals the thread to exit and returns once the thread has exited. After
// this method returns, the Thread object is completely reset and may be used
// as if it were newly constructed (i.e., Start may be called again).
//
// Stop may be called multiple times and is simply ignored if the thread is
// already stopped.
//
// NOTE: If you are a consumer of Thread, it is not necessary to call this
// before deleting your Thread objects, as the destructor will do it.
// IF YOU ARE A SUBCLASS OF Thread, YOU MUST CALL THIS IN YOUR DESTRUCTOR.
void Stop();
// Signals the thread to exit in the near future.
//
// WARNING: This function is not meant to be commonly used. Use at your own
// risk. Calling this function will cause message_loop() to become invalid in
// the near future. This function was created to workaround a specific
// deadlock on Windows with printer worker thread. In any other case, Stop()
// should be used.
//
// StopSoon should not be called multiple times as it is risky to do so. It
// could cause a timing issue in message_loop() access. Call Stop() to reset
// the thread object once it is known that the thread has quit.
void StopSoon();
// Returns the message loop for this thread. Use the MessageLoop's
// PostTask methods to execute code on the thread. This only returns
// non-null after a successful call to Start. After Stop has been called,
// this will return NULL.
//
// NOTE: You must not call this MessageLoop's Quit method directly. Use
// the Thread's Stop method instead.
//
MessageLoop* message_loop() const { return message_loop_; }
// Returns a MessageLoopProxy for this thread. Use the MessageLoopProxy's
// PostTask methods to execute code on the thread. This only returns
// non-NULL after a successful call to Start. After Stop has been called,
// this will return NULL. Callers can hold on to this even after the thread
// is gone.
scoped_refptr<MessageLoopProxy> message_loop_proxy() const {
return message_loop_ ? message_loop_->message_loop_proxy() : NULL;
}
// Returns the name of this thread (for display in debugger too).
const std::string& thread_name() const { return name_; }
// The native thread handle.
PlatformThreadHandle thread_handle() { return thread_; }
// The thread ID.
PlatformThreadId thread_id() const { return thread_id_; }
// Returns true if the thread has been started, and not yet stopped.
bool IsRunning() const;
// Sets the thread priority. The thread must already be started.
void SetPriority(ThreadPriority priority);
protected:
// Called just prior to starting the message loop
virtual void Init() {}
// Called to start the message loop
virtual void Run(MessageLoop* message_loop);
// Called just after the message loop ends
virtual void CleanUp() {}
static void SetThreadWasQuitProperly(bool flag);
static bool GetThreadWasQuitProperly();
void set_message_loop(MessageLoop* message_loop) {
message_loop_ = message_loop;
}
private:
#if defined(OS_WIN)
enum ComStatus {
NONE,
STA,
MTA,
};
#endif
// PlatformThread::Delegate methods:
virtual void ThreadMain() OVERRIDE;
#if defined(OS_WIN)
// Whether this thread needs to initialize COM, and if so, in what mode.
ComStatus com_status_;
#endif
// Whether we successfully started the thread.
bool started_;
// If true, we're in the middle of stopping, and shouldn't access
// |message_loop_|. It may non-NULL and invalid.
bool stopping_;
// True while inside of Run().
bool running_;
// Used to pass data to ThreadMain.
struct StartupData;
StartupData* startup_data_;
// The thread's handle.
PlatformThreadHandle thread_;
// The thread's message loop. Valid only while the thread is alive. Set
// by the created thread.
MessageLoop* message_loop_;
// Our thread's ID.
PlatformThreadId thread_id_;
// The name of the thread. Used for debugging purposes.
std::string name_;
friend void ThreadQuitHelper();
DISALLOW_COPY_AND_ASSIGN(Thread);
};
} // namespace base
#endif // BASE_THREADING_THREAD_H_
|