![]() |
![]() |
00001 /* 00002 * Glib::Dispatcher example -- cross thread signalling 00003 * by Daniel Elstner <daniel.elstner@gmx.net> 00004 * 00005 * modified to only use glibmm 00006 * by J. Abelardo Gutierrez <jabelardo@cantv.net> 00007 * 00008 * Copyright (c) 2002-2003 Free Software Foundation 00009 */ 00010 00011 #include <glibmm.h> 00012 00013 #include <algorithm> 00014 #include <functional> 00015 #include <iostream> 00016 #include <list> 00017 #include <memory> 00018 00019 00020 namespace 00021 { 00022 00023 class ThreadProgress : public sigc::trackable 00024 { 00025 public: 00026 explicit ThreadProgress(int id); 00027 virtual ~ThreadProgress(); 00028 00029 void launch(); 00030 void join(); 00031 00032 sigc::signal<void>& signal_finished(); 00033 int id() const; 00034 00035 virtual void reference() const { ++ref_count_; } 00036 virtual void unreference() const { if (!(--ref_count_)) delete this; } 00037 00038 private: 00039 Glib::Thread* thread_; 00040 int id_; 00041 unsigned int progress_; 00042 Glib::Dispatcher signal_increment_; 00043 sigc::signal<void> signal_finished_; 00044 00045 void progress_increment(); 00046 void thread_function(); 00047 00048 mutable int ref_count_; 00049 00050 }; 00051 00052 class Application : public sigc::trackable 00053 { 00054 public: 00055 Application(); 00056 virtual ~Application(); 00057 00058 void launch_threads(); 00059 void run(); 00060 00061 private: 00062 Glib::RefPtr<Glib::MainLoop> main_loop_; 00063 std::list<ThreadProgress*> progress_list_; 00064 std::list<Glib::RefPtr<ThreadProgress> > progress_ref_list_; 00065 00066 void on_progress_finished(ThreadProgress* thread_progress); 00067 }; 00068 00069 00070 ThreadProgress::ThreadProgress(int id) 00071 : 00072 thread_ (0), 00073 id_ (id), 00074 progress_ (0), 00075 ref_count_(0) 00076 { 00077 // Increment the reference count 00078 reference(); 00079 // Connect to the cross-thread signal. 00080 signal_increment_.connect(sigc::mem_fun(*this, &ThreadProgress::progress_increment)); 00081 } 00082 00083 ThreadProgress::~ThreadProgress() 00084 {} 00085 00086 void ThreadProgress::launch() 00087 { 00088 // Create a joinable thread. 00089 thread_ = Glib::Thread::create(sigc::mem_fun(*this, &ThreadProgress::thread_function), true); 00090 } 00091 00092 void ThreadProgress::join() 00093 { 00094 thread_->join(); 00095 } 00096 00097 sigc::signal<void>& ThreadProgress::signal_finished() 00098 { 00099 return signal_finished_; 00100 } 00101 00102 int ThreadProgress::id() const 00103 { 00104 return id_; 00105 } 00106 00107 void ThreadProgress::progress_increment() 00108 { 00109 // Use an integer because floating point arithmetic is inaccurate -- 00110 // we want to finish *exactly* after the 100th increment. 00111 ++progress_; 00112 00113 std::cout << "Thread " << id_ << ": " << progress_ << '%' << std::endl; 00114 00115 if(progress_ >= 100) 00116 signal_finished_(); 00117 } 00118 00119 void ThreadProgress::thread_function() 00120 { 00121 Glib::Rand rand; 00122 int usecs = 5000; 00123 00124 for(int i = 0; i < 100; ++i) 00125 { 00126 usecs = rand.get_int_range(std::max(0, usecs - 1000 - i), std::min(20000, usecs + 1000 + i)); 00127 Glib::usleep(usecs); 00128 00129 // Tell the main thread to increment the progress value. 00130 signal_increment_(); 00131 } 00132 } 00133 00134 Application::Application() 00135 : 00136 main_loop_ (Glib::MainLoop::create()) 00137 { 00138 std::cout << "Thread Dispatcher Example." << std::endl; 00139 00140 for(int i = 1; i <= 5; ++i) 00141 { 00142 ThreadProgress* progress=new ThreadProgress(i); 00143 progress_list_.push_back(progress); 00144 progress_ref_list_.push_back(Glib::RefPtr<ThreadProgress>(progress)); 00145 00146 progress->signal_finished().connect( 00147 sigc::bind<1>(sigc::mem_fun(*this, &Application::on_progress_finished), progress)); 00148 } 00149 } 00150 00151 Application::~Application() 00152 { 00153 } 00154 00155 void Application::launch_threads() 00156 { 00157 std::for_each(progress_list_.begin(), progress_list_.end(), 00158 std::mem_fun(&ThreadProgress::launch)); 00159 } 00160 00161 void Application::run() 00162 { 00163 main_loop_->run(); 00164 } 00165 00166 void Application::on_progress_finished(ThreadProgress* thread_progress) 00167 { 00168 { 00169 progress_list_.remove(thread_progress); 00170 thread_progress->join(); 00171 00172 std::cout << "Thread " << thread_progress->id() 00173 << ": finished." << std::endl; 00174 } 00175 00176 if(progress_list_.empty()) 00177 main_loop_->quit(); 00178 } 00179 00180 } // anonymous namespace 00181 00182 00183 int main(int, char**) 00184 { 00185 Glib::thread_init(); 00186 00187 Application application; 00188 00189 // Install a one-shot idle handler to launch the threads 00190 Glib::signal_idle().connect( 00191 sigc::bind_return(sigc::mem_fun(application, &Application::launch_threads), false)); 00192 00193 application.run(); 00194 00195 return 0; 00196 } 00197