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