signalthread.h revision f74420b3285b9fe04a7e00aa3b8c0ab07ea344bc
1/* 2 * libjingle 3 * Copyright 2004--2009, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#ifndef TALK_BASE_SIGNALTHREAD_H_ 29#define TALK_BASE_SIGNALTHREAD_H_ 30 31#include "talk/base/thread.h" 32#include "talk/base/sigslot.h" 33 34namespace talk_base { 35 36/////////////////////////////////////////////////////////////////////////////// 37// SignalThread - Base class for worker threads. The main thread should call 38// Start() to begin work, and then follow one of these models: 39// Normal: Wait for SignalWorkDone, and then call Release to destroy. 40// Cancellation: Call Release(true), to abort the worker thread. 41// Fire-and-forget: Call Release(false), which allows the thread to run to 42// completion, and then self-destruct without further notification. 43// Periodic tasks: Wait for SignalWorkDone, then eventually call Start() 44// again to repeat the task. When the instance isn't needed anymore, 45// call Release. DoWork, OnWorkStart and OnWorkStop are called again, 46// on a new thread. 47// The subclass should override DoWork() to perform the background task. By 48// periodically calling ContinueWork(), it can check for cancellation. 49// OnWorkStart and OnWorkDone can be overridden to do pre- or post-work 50// tasks in the context of the main thread. 51/////////////////////////////////////////////////////////////////////////////// 52 53class SignalThread : public sigslot::has_slots<>, protected MessageHandler { 54 public: 55 SignalThread(); 56 57 // Context: Main Thread. Call before Start to change the worker's priority. 58 void SetPriority(ThreadPriority priority); 59 60 // Context: Main Thread. Call to begin the worker thread. 61 void Start(); 62 63 // Context: Main Thread. If the worker thread is not running, deletes the 64 // object immediately. Otherwise, asks the worker thread to abort processing, 65 // and schedules the object to be deleted once the worker exits. 66 // SignalWorkDone will not be signalled. If wait is true, does not return 67 // until the thread is deleted. 68 void Destroy(bool wait); 69 70 // Context: Main Thread. If the worker thread is complete, deletes the 71 // object immediately. Otherwise, schedules the object to be deleted once 72 // the worker thread completes. SignalWorkDone will be signalled. 73 void Release(); 74 75 // Context: Main Thread. Signalled when work is complete. 76 sigslot::signal1<SignalThread *> SignalWorkDone; 77 78 enum { ST_MSG_WORKER_DONE, ST_MSG_FIRST_AVAILABLE }; 79 80 protected: 81 virtual ~SignalThread(); 82 83 Thread* worker() { return &worker_; } 84 85 // Context: Main Thread. Subclass should override to do pre-work setup. 86 virtual void OnWorkStart() { } 87 88 // Context: Worker Thread. Subclass should override to do work. 89 virtual void DoWork() = 0; 90 91 // Context: Worker Thread. Subclass should call periodically to 92 // dispatch messages and determine if the thread should terminate. 93 bool ContinueWork(); 94 95 // Context: Worker Thread. Subclass should override when extra work is 96 // needed to abort the worker thread. 97 virtual void OnWorkStop() { } 98 99 // Context: Main Thread. Subclass should override to do post-work cleanup. 100 virtual void OnWorkDone() { } 101 102 // Context: Any Thread. If subclass overrides, be sure to call the base 103 // implementation. Do not use (message_id < ST_MSG_FIRST_AVAILABLE) 104 virtual void OnMessage(Message *msg); 105 106 private: 107 enum State { 108 kInit, // Initialized, but not started 109 kRunning, // Started and doing work 110 kReleasing, // Same as running, but to be deleted when work is done 111 kComplete, // Work is done 112 kStopping, // Work is being interrupted 113 }; 114 115 friend class Worker; 116 class Worker : public Thread { 117 public: 118 SignalThread* parent_; 119 virtual void Run() { parent_->Run(); } 120 }; 121 122 friend class EnterExit; 123 class EnterExit { 124 public: 125 explicit EnterExit(SignalThread* t) : t_(t) { 126 t_->cs_.Enter(); 127 t_->refcount_ += 1; 128 } 129 ~EnterExit() { 130 bool d = (0 == (--(t_->refcount_))); 131 t_->cs_.Leave(); 132 if (d) 133 delete t_; 134 } 135 private: 136 SignalThread* t_; 137 }; 138 139 void Run(); 140 void OnMainThreadDestroyed(); 141 142 Thread* main_; 143 Worker worker_; 144 CriticalSection cs_; 145 State state_; 146 int refcount_; 147}; 148 149/////////////////////////////////////////////////////////////////////////////// 150 151} // namespace talk_base 152 153#endif // TALK_BASE_SIGNALTHREAD_H_ 154