logo top
Main Page   Widgets   glibmm Namespaces   Book  

thread/dispatcher.cc

A Glib::Dispatcher example.

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 

Generated for glibmm 2.4 by Doxygen 1.5.1 © 1997-2001