OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 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 // WARNING: You should probably be using Thread (thread.h) instead. Thread is | |
6 // Chrome's message-loop based Thread abstraction, and if you are a | |
7 // thread running in the browser, there will likely be assumptions | |
8 // that your thread will have an associated message loop. | |
9 // | |
10 // This is a simple thread interface that backs to a native operating system | |
11 // thread. You should use this only when you want a thread that does not have | |
12 // an associated MessageLoop. Unittesting is the best example of this. | |
13 // | |
14 // The simplest interface to use is DelegateSimpleThread, which will create | |
15 // a new thread, and execute the Delegate's virtual Run() in this new thread | |
16 // until it has completed, exiting the thread. | |
17 // | |
18 // NOTE: You *MUST* call Join on the thread to clean up the underlying thread | |
19 // resources. You are also responsible for destructing the SimpleThread object. | |
20 // It is invalid to destroy a SimpleThread while it is running, or without | |
21 // Start() having been called (and a thread never created). The Delegate | |
22 // object should live as long as a DelegateSimpleThread. | |
23 // | |
24 // Thread Safety: A SimpleThread is not completely thread safe. It is safe to | |
25 // access it from the creating thread or from the newly created thread. This | |
26 // implies that the creator thread should be the thread that calls Join. | |
27 // | |
28 // Example: | |
29 // class MyThreadRunner : public DelegateSimpleThread::Delegate { ... }; | |
30 // MyThreadRunner runner; | |
31 // DelegateSimpleThread thread(&runner, "good_name_here"); | |
32 // thread.Start(); | |
33 // // Start will return after the Thread has been successfully started and | |
34 // // initialized. The newly created thread will invoke runner->Run(), and | |
35 // // run until it returns. | |
36 // thread.Join(); // Wait until the thread has exited. You *MUST* Join! | |
37 // // The SimpleThread object is still valid, however you may not call Join | |
38 // // or Start again. | |
39 | |
40 #ifndef BASE_SIMPLE_THREAD_H_ | |
41 #define BASE_SIMPLE_THREAD_H_ | |
42 #pragma once | |
43 | |
44 #include <string> | |
45 #include <queue> | |
46 #include <vector> | |
47 | |
48 #include "base/basictypes.h" | |
49 #include "base/lock.h" | |
50 #include "base/waitable_event.h" | |
51 #include "base/platform_thread.h" | |
52 | |
53 namespace base { | |
54 | |
55 // This is the base SimpleThread. You can derive from it and implement the | |
56 // virtual Run method, or you can use the DelegateSimpleThread interface. | |
57 class SimpleThread : public PlatformThread::Delegate { | |
58 public: | |
59 class Options { | |
60 public: | |
61 Options() : stack_size_(0) { } | |
62 ~Options() { } | |
63 | |
64 // We use the standard compiler-supplied copy constructor. | |
65 | |
66 // A custom stack size, or 0 for the system default. | |
67 void set_stack_size(size_t size) { stack_size_ = size; } | |
68 size_t stack_size() const { return stack_size_; } | |
69 private: | |
70 size_t stack_size_; | |
71 }; | |
72 | |
73 // Create a SimpleThread. |options| should be used to manage any specific | |
74 // configuration involving the thread creation and management. | |
75 // Every thread has a name, in the form of |name_prefix|/TID, for example | |
76 // "my_thread/321". The thread will not be created until Start() is called. | |
77 explicit SimpleThread(const std::string& name_prefix); | |
78 SimpleThread(const std::string& name_prefix, const Options& options); | |
79 | |
80 virtual ~SimpleThread(); | |
81 | |
82 virtual void Start(); | |
83 virtual void Join(); | |
84 | |
85 // We follow the PlatformThread Delegate interface. | |
86 virtual void ThreadMain(); | |
87 | |
88 // Subclasses should override the Run method. | |
89 virtual void Run() = 0; | |
90 | |
91 // Return the thread name prefix, or "unnamed" if none was supplied. | |
92 std::string name_prefix() { return name_prefix_; } | |
93 | |
94 // Return the completed name including TID, only valid after Start(). | |
95 std::string name() { return name_; } | |
96 | |
97 // Return the thread id, only valid after Start(). | |
98 PlatformThreadId tid() { return tid_; } | |
99 | |
100 // Return True if Start() has ever been called. | |
101 bool HasBeenStarted() { return event_.IsSignaled(); } | |
102 | |
103 // Return True if Join() has evern been called. | |
104 bool HasBeenJoined() { return joined_; } | |
105 | |
106 private: | |
107 const std::string name_prefix_; | |
108 std::string name_; | |
109 const Options options_; | |
110 PlatformThreadHandle thread_; // PlatformThread handle, invalid after Join! | |
111 WaitableEvent event_; // Signaled if Start() was ever called. | |
112 PlatformThreadId tid_; // The backing thread's id. | |
113 bool joined_; // True if Join has been called. | |
114 }; | |
115 | |
116 class DelegateSimpleThread : public SimpleThread { | |
117 public: | |
118 class Delegate { | |
119 public: | |
120 Delegate() { } | |
121 virtual ~Delegate() { } | |
122 virtual void Run() = 0; | |
123 }; | |
124 | |
125 DelegateSimpleThread(Delegate* delegate, | |
126 const std::string& name_prefix); | |
127 DelegateSimpleThread(Delegate* delegate, | |
128 const std::string& name_prefix, | |
129 const Options& options); | |
130 | |
131 virtual ~DelegateSimpleThread(); | |
132 virtual void Run(); | |
133 private: | |
134 Delegate* delegate_; | |
135 }; | |
136 | |
137 // DelegateSimpleThreadPool allows you to start up a fixed number of threads, | |
138 // and then add jobs which will be dispatched to the threads. This is | |
139 // convenient when you have a lot of small work that you want done | |
140 // multi-threaded, but don't want to spawn a thread for each small bit of work. | |
141 // | |
142 // You just call AddWork() to add a delegate to the list of work to be done. | |
143 // JoinAll() will make sure that all outstanding work is processed, and wait | |
144 // for everything to finish. You can reuse a pool, so you can call Start() | |
145 // again after you've called JoinAll(). | |
146 class DelegateSimpleThreadPool : public DelegateSimpleThread::Delegate { | |
147 public: | |
148 typedef DelegateSimpleThread::Delegate Delegate; | |
149 | |
150 DelegateSimpleThreadPool(const std::string& name_prefix, int num_threads); | |
151 virtual ~DelegateSimpleThreadPool(); | |
152 | |
153 // Start up all of the underlying threads, and start processing work if we | |
154 // have any. | |
155 void Start(); | |
156 | |
157 // Make sure all outstanding work is finished, and wait for and destroy all | |
158 // of the underlying threads in the pool. | |
159 void JoinAll(); | |
160 | |
161 // It is safe to AddWork() any time, before or after Start(). | |
162 // Delegate* should always be a valid pointer, NULL is reserved internally. | |
163 void AddWork(Delegate* work, int repeat_count); | |
164 void AddWork(Delegate* work) { | |
165 AddWork(work, 1); | |
166 } | |
167 | |
168 // We implement the Delegate interface, for running our internal threads. | |
169 virtual void Run(); | |
170 | |
171 private: | |
172 const std::string name_prefix_; | |
173 int num_threads_; | |
174 std::vector<DelegateSimpleThread*> threads_; | |
175 std::queue<Delegate*> delegates_; | |
176 Lock lock_; // Locks delegates_ | |
177 WaitableEvent dry_; // Not signaled when there is no work to do. | |
178 }; | |
179 | |
180 } // namespace base | |
181 | |
182 #endif // BASE_SIMPLE_THREAD_H_ | |
OLD | NEW |