397 | | === 4.6 How does rendering work? [=#q4.6] === |
| 398 | === 4.6 How is threading done? [=#q4.6] === |
| 399 | |
| 400 | It uses [http://developer.gnome.org/glib/2.30/glib-Threads.html Gtkmm threading system] and implements worker classes which do the work in separate threads, without blocking the GUI. All worker classes inherit from {{{Worker.h}}} which is pretty simple. It provides a {{{start()}}} method with launches a new thread and a virtual {{{run()}}} method with code to be executed. It also has a {{{Glib::Dispatcher}}} object for inter-thread communication (works like signals). |
| 401 | |
| 402 | {{{ |
| 403 | #!div style="font-size: 100%" |
| 404 | {{{#!c++ |
| 405 | class Worker |
| 406 | { |
| 407 | public: |
| 408 | Worker() : thread(0), stopped(false) {} |
| 409 | |
| 410 | virtual ~Worker() |
| 411 | { |
| 412 | { |
| 413 | Glib::Mutex::Lock lock (mutex); |
| 414 | stopped = true; |
| 415 | } |
| 416 | if (thread) |
| 417 | thread->join(); |
| 418 | } |
| 419 | |
| 420 | void start() |
| 421 | { |
| 422 | thread = Glib::Thread::create(sigc::mem_fun(*this, &Worker::run), true); |
| 423 | } |
| 424 | |
| 425 | Glib::Dispatcher sig_done; |
| 426 | |
| 427 | protected: |
| 428 | virtual void run() = 0; |
| 429 | |
| 430 | Glib::Thread* thread; |
| 431 | Glib::Mutex mutex; |
| 432 | bool stopped; |
| 433 | }; |
| 434 | }}} |
| 435 | }}} |
| 436 | |
| 437 | Each GUI class which uses threads has a {{{Worker}}} member initially set to null. Then once a function that starts the work is called the worker is created and started, and signal handlers are connected to handle the {{{Dispatcher}}} objects: |
| 438 | |
| 439 | {{{ |
| 440 | #!div style="font-size: 100%" |
| 441 | {{{#!c++ |
| 442 | // Check if we don't already have a thread running |
| 443 | if (worker != NULL) return; |
| 444 | |
| 445 | // Create a new worker |
| 446 | worker = new Worker(...) |
| 447 | // Start the worker |
| 448 | worker->start() |
| 449 | // Connect signals |
| 450 | worker->sig_done().connect(sigc::mem_fun(*this, &GUIClass::on_worker_work_finished)); |
| 451 | |
| 452 | // Display a progress bar or a busy cursor |
| 453 | }}} |
| 454 | }}} |
| 455 | |
| 456 | Once the worker has finished it emits {{{sig_done()}}} signal in its {{{run()}}} method notifying the caller class and {{{on_worker_work_finished()}}} method gets called. Most worker classes implement more signals to notify about different events (for example load progress to move the progress bar). The idea stays the same though. \\ \\ |
| 457 | Additionally in GUI classes {{{Glib::Mutex}}} objects are used at the beginning of each critical section to avoid race conditions. Using brackets around the section makes sure that the {{{Mutex::Lock}}} object get automatically destroyed. |
| 458 | |
| 459 | {{{ |
| 460 | #!div style="font-size: 100%" |
| 461 | {{{#!c++ |
| 462 | // some non critical code |
| 463 | |
| 464 | { |
| 465 | Glib::Mutex::Lock lock (mutex) // mutex is a class member |
| 466 | // critical code |
| 467 | } // lock gets destroyed here |
| 468 | }}} |
| 469 | }}} |
| 470 | |
| 471 | === 4.7 How does rendering work? [=#q4.7] === |