Example Documentation

Main Page Widgets Namespaces Book

# thread/dispatcher.cc

A Glib::Dispatcher example.

    /*
     * Glib::Dispatcher example -- cross thread signalling
     * by Daniel Elstner  <daniel.elstner@gmx.net>
     *
     * modified to only use glibmm
     * by J. Abelardo Gutierrez <jabelardo@cantv.net>
     *
     * Copyright (c) 2002-2003  Free Software Foundation
     */

    #include <glibmm.h>

    #include <algorithm>
    #include <functional>
    #include <iostream>
    #include <list>
    #include <memory>

    namespace
    {

    class ThreadProgress
    {
    public:
      explicit ThreadProgress(int id);
      ~ThreadProgress();

      void launch();
      void join();

      sigc::signal<void>& signal_finished();
      int id() const;

    private:
      Glib::Thread*       thread_;
      int                 id_;
      unsigned int        progress_;
      Glib::Dispatcher    signal_increment_;
      sigc::signal<void>  signal_finished_;

      void progress_increment();
      void thread_function();
    };

    class Application : public sigc::trackable
    {
    public:
      Application();
      virtual ~Application();

      void launch_threads();
      void run();

    private:
      Glib::RefPtr<Glib::MainLoop>  main_loop_;
      std::list<ThreadProgress*>    progress_list_;

      void on_progress_finished(ThreadProgress* thread_progress);
    };

    ThreadProgress::ThreadProgress(int id)
    :
      thread_   (0),
      id_       (id),
      progress_ (0)
    {
      // Connect to the cross-thread signal.
      signal_increment_.connect(sigc::mem_fun(*this, &ThreadProgress::progress_increment));
    }

    ThreadProgress::~ThreadProgress()
    {}

    void ThreadProgress::launch()
    {
      // Create a joinable thread.
      thread_ = Glib::Thread::create(sigc::mem_fun(*this, &ThreadProgress::thread_function), true);
    }

    void ThreadProgress::join()
    {
      thread_->join();
    }

    sigc::signal<void>& ThreadProgress::signal_finished()
    {
      return signal_finished_;
    }

    int ThreadProgress::id() const
    {
      return id_;
    }

    void ThreadProgress::progress_increment()
    {
      // Use an integer because floating point arithmetic is inaccurate --
      // we want to finish *exactly* after the 100th increment.
      ++progress_;

      std::cout << "Thread " << id_ << ": " << progress_ << '%' << std::endl;

      if(progress_ >= 100)
        signal_finished_();
    }

    void ThreadProgress::thread_function()
    {
      Glib::Rand rand;
      int usecs = 5000;

      for(int i = 0; i < 100; ++i)
      {
        usecs = rand.get_int_range(std::max(0, usecs - 1000 - i), std::min(20000, usecs + 1000 + i));
        Glib::usleep(usecs);

        // Tell the main thread to increment the progress value.
        signal_increment_();
      }
    }

    Application::Application()
    :
      main_loop_ (Glib::MainLoop::create())
    {
      std::cout << "Thread Dispatcher Example." << std::endl;

      for(int i = 1; i <= 5; ++i)
      {
        std::auto_ptr<ThreadProgress> progress (new ThreadProgress(i));
        progress_list_.push_back(progress.get());

        progress->signal_finished().connect(
            sigc::bind(sigc::mem_fun(*this, &Application::on_progress_finished), progress.release()));
      }
    }

    Application::~Application()
    {}

    void Application::launch_threads()
    {
      std::for_each(progress_list_.begin(), progress_list_.end(),
                    std::mem_fun(&ThreadProgress::launch));
    }

    void Application::run()
    {
      main_loop_->run();
    }

    void Application::on_progress_finished(ThreadProgress* thread_progress)
    {
      {
        const std::auto_ptr<ThreadProgress> progress (thread_progress);

        progress_list_.remove(progress.get());
        progress->join();

        std::cout << "Thread " << progress->id() << ": finished." << std::endl;
      }

      if(progress_list_.empty())
        main_loop_->quit();
    }

    } // anonymous namespace

    int main(int, char**)
    {
      Glib::thread_init();

      Application application;

      // Install a one-shot idle handler to launch the threads
      Glib::signal_idle().connect(
          sigc::bind_return(sigc::mem_fun(application, &Application::launch_threads), false));

      application.run();

      return 0;
    }

    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
    00024 {
    00025 public:
    00026   explicit ThreadProgress(int id);
    00027   ~ThreadProgress();
    00028
    00029   void launch();
    00030   void join();
    00031
    00032   sigc::signal<void>& signal_finished();
    00033   int id() const;
    00034
    00035 private:
    00036   Glib::Thread*       thread_;
    00037   int                 id_;
    00038   unsigned int        progress_;
    00039   Glib::Dispatcher    signal_increment_;
    00040   sigc::signal<void>  signal_finished_;
    00041
    00042   void progress_increment();
    00043   void thread_function();
    00044 };
    00045
    00046 class Application : public sigc::trackable
    00047 {
    00048 public:
    00049   Application();
    00050   virtual ~Application();
    00051
    00052   void launch_threads();
    00053   void run();
    00054
    00055 private:
    00056   Glib::RefPtr<Glib::MainLoop>  main_loop_;
    00057   std::list<ThreadProgress*>    progress_list_;
    00058
    00059   void on_progress_finished(ThreadProgress* thread_progress);
    00060 };
    00061
    00062
    00063 ThreadProgress::ThreadProgress(int id)
    00064 :
    00065   thread_   (0),
    00066   id_       (id),
    00067   progress_ (0)
    00068 {
    00069   // Connect to the cross-thread signal.
    00070   signal_increment_.connect(sigc::mem_fun(*this, &ThreadProgress::progress_increment));
    00071 }
    00072
    00073 ThreadProgress::~ThreadProgress()
    00074 {}
    00075
    00076 void ThreadProgress::launch()
    00077 {
    00078   // Create a joinable thread.
    00079   thread_ = Glib::Thread::create(sigc::mem_fun(*this, &ThreadProgress::thread_function), true);
    00080 }
    00081
    00082 void ThreadProgress::join()
    00083 {
    00084   thread_->join();
    00085 }
    00086
    00087 sigc::signal<void>& ThreadProgress::signal_finished()
    00088 {
    00089   return signal_finished_;
    00090 }
    00091
    00092 int ThreadProgress::id() const
    00093 {
    00094   return id_;
    00095 }
    00096
    00097 void ThreadProgress::progress_increment()
    00098 {
    00099   // Use an integer because floating point arithmetic is inaccurate --
    00100   // we want to finish *exactly* after the 100th increment.
    00101   ++progress_;
    00102
    00103   std::cout << "Thread " << id_ << ": " << progress_ << '%' << std::endl;
    00104
    00105   if(progress_ >= 100)
    00106     signal_finished_();
    00107 }
    00108
    00109 void ThreadProgress::thread_function()
    00110 {
    00111   Glib::Rand rand;
    00112   int usecs = 5000;
    00113
    00114   for(int i = 0; i < 100; ++i)
    00115   {
    00116     usecs = rand.get_int_range(std::max(0, usecs - 1000 - i), std::min(20000, usecs + 1000 + i));
    00117     Glib::usleep(usecs);
    00118
    00119     // Tell the main thread to increment the progress value.
    00120     signal_increment_();
    00121   }
    00122 }
    00123
    00124 Application::Application()
    00125 :
    00126   main_loop_ (Glib::MainLoop::create())
    00127 {
    00128   std::cout << "Thread Dispatcher Example." << std::endl;
    00129
    00130   for(int i = 1; i <= 5; ++i)
    00131   {
    00132     std::auto_ptr<ThreadProgress> progress (new ThreadProgress(i));
    00133     progress_list_.push_back(progress.get());
    00134
    00135     progress->signal_finished().connect(
    00136         sigc::bind(sigc::mem_fun(*this, &Application::on_progress_finished), progress.release()));
    00137   }
    00138 }
    00139
    00140 Application::~Application()
    00141 {}
    00142
    00143 void Application::launch_threads()
    00144 {
    00145   std::for_each(progress_list_.begin(), progress_list_.end(),
    00146                 std::mem_fun(&ThreadProgress::launch));
    00147 }
    00148
    00149 void Application::run()
    00150 {
    00151   main_loop_->run();
    00152 }
    00153
    00154 void Application::on_progress_finished(ThreadProgress* thread_progress)
    00155 {
    00156   {
    00157     const std::auto_ptr<ThreadProgress> progress (thread_progress);
    00158
    00159     progress_list_.remove(progress.get());
    00160     progress->join();
    00161
    00162     std::cout << "Thread " << progress->id() << ": finished." << std::endl;
    00163   }
    00164
    00165   if(progress_list_.empty())
    00166     main_loop_->quit();
    00167 }
    00168
    00169 } // anonymous namespace
    00170
    00171
    00172 int main(int, char**)
    00173 {
    00174   Glib::thread_init();
    00175
    00176   Application application;
    00177
    00178   // Install a one-shot idle handler to launch the threads
    00179   Glib::signal_idle().connect(
    00180       sigc::bind_return(sigc::mem_fun(application, &Application::launch_threads), false));
    00181
    00182   application.run();
    00183
    00184   return 0;
    00185 }
    00186