2 * original Glib::Dispatcher example -- cross thread signalling
3 * by Daniel Elstner <daniel.elstner@gmx.net>
5 * Modified by Stephan Puchegger <stephan.puchegger@ap.univie.ac.at>
6 * to contain 2 mainloops in 2 different threads, that communicate
7 * via cross thread signalling in both directions. The timer thread
8 * sends the UI thread a cross thread signal every second, which in turn
9 * updates the label stating how many seconds have passed since the start
12 * Modified by J. Abelardo Gutierrez <jabelardo@cantv.net>
13 * to cast all gtkmm out and make it glimm only
15 * Note: This example is special stuff that's seldomly needed by the
16 * vast majority of applications. Don't bother working out what this
17 * code does unless you know for sure you need 2 main loops running in
18 * 2 distinct main contexts.
20 * Copyright (c) 2002-2003 Free Software Foundation
30 Glib::RefPtr<Glib::MainLoop> main_loop;
32 class ThreadTimer : public sigc::trackable
39 void signal_finished_emit();
42 typedef sigc::signal<void> type_signal_end;
43 static type_signal_end& signal_end();
47 Glib::Dispatcher signal_increment_;
48 Glib::Dispatcher* signal_finished_ptr_;
50 Glib::Mutex startup_mutex_;
51 Glib::Cond startup_cond_;
52 Glib::Thread* thread_;
54 static type_signal_end signal_end_;
56 void timer_increment();
57 bool timeout_handler();
58 static void finished_handler(Glib::RefPtr<Glib::MainLoop> mainloop);
59 void thread_function();
62 //TODO: Rename to avoid confusion with Glib::Dispatcher. murrayc
63 class Dispatcher : public sigc::trackable
75 ThreadTimer::ThreadTimer()
78 // Create a new dispatcher that is attached to the default main context,
80 // This pointer will be initialized later by the 2nd thread.
81 signal_finished_ptr_ (NULL)
83 // Connect the cross-thread signal.
84 signal_increment_.connect(sigc::mem_fun(*this, &ThreadTimer::timer_increment));
87 ThreadTimer::~ThreadTimer()
90 void ThreadTimer::launch()
92 // Unfortunately, the thread creation has to be fully synchronized in
93 // order to access the Dispatcher object instantiated by the 2nd thread.
94 // So, let's do some kind of hand-shake using a mutex and a condition
96 Glib::Mutex::Lock lock (startup_mutex_);
98 // Create a joinable thread -- it needs to be joined, otherwise it's a memory leak.
99 thread_ = Glib::Thread::create(
100 sigc::mem_fun(*this, &ThreadTimer::thread_function), true);
102 // Wait for the 2nd thread's startup notification.
103 while(signal_finished_ptr_ == NULL)
104 startup_cond_.wait(startup_mutex_);
107 void ThreadTimer::signal_finished_emit()
109 // Cause the 2nd thread's main loop to quit.
110 signal_finished_ptr_->emit();
112 // wait for the thread to join
116 signal_finished_ptr_ = NULL;
119 void ThreadTimer::print() const
121 std::cout << time_ << " seconds since start" << std::endl;
124 sigc::signal< void >& ThreadTimer::signal_end()
129 void ThreadTimer::timer_increment()
131 // another second has passed since the start of the program
136 signal_finished_emit();
140 void ThreadTimer::finished_handler(Glib::RefPtr<Glib::MainLoop> mainloop)
142 // quit the timer thread mainloop
144 std::cout << "timer thread mainloop finished" << std::endl;
145 ThreadTimer::signal_end().emit();
148 bool ThreadTimer::timeout_handler()
150 // inform the printing thread that another second has passed
153 // this timer should stay alive
157 void ThreadTimer::thread_function()
159 // create a new Main Context
160 Glib::RefPtr<Glib::MainContext> context = Glib::MainContext::create();
161 // create a new Main Loop
162 Glib::RefPtr<Glib::MainLoop> mainloop = Glib::MainLoop::create(context, true);
164 // attach a timeout handler, that is called every second, to the
165 // newly created MainContext
166 context->signal_timeout().connect(sigc::mem_fun(*this, &ThreadTimer::timeout_handler), 1000);
168 // We need to lock while creating the Dispatcher instance,
169 // in order to ensure memory visibility.
170 Glib::Mutex::Lock lock (startup_mutex_);
172 // create a new dispatcher, that is connected to the newly
173 // created MainContext
174 Glib::Dispatcher signal_finished (context);
176 signal_finished.connect(sigc::bind(sigc::ptr_fun(&ThreadTimer::finished_handler), mainloop));
178 signal_finished_ptr_ = &signal_finished;
180 // Tell the launcher thread that everything is in place now.
181 startup_cond_.signal();
184 // start the mainloop
188 // initialize static member:
189 ThreadTimer::type_signal_end ThreadTimer::signal_end_;
191 Dispatcher::Dispatcher()
195 std::cout << "Thread Dispatcher Example #2" << std::endl;
197 timer_ = new ThreadTimer();
198 timer_->signal_end().connect(sigc::mem_fun(*this, &Dispatcher::end));
202 void Dispatcher::launch_thread()
204 // launch the timer thread
208 void Dispatcher::end()
210 // quit the main mainloop
214 } // anonymous namespace
217 int main(int, char**)
220 main_loop = Glib::MainLoop::create();
222 Dispatcher dispatcher;
224 // Install a one-shot idle handler to launch the threads
225 Glib::signal_idle().connect(
226 sigc::bind_return(sigc::mem_fun(dispatcher, &Dispatcher::launch_thread), false));