ディスパッチャ

概要

ディスパッチャを使う

GUIプログラミングでは子スレッドが完了したことをメインスレッドに知らせたり、子スレッド内ではなく メインスレッド内で関数を実行させたいときがあるが、これには Glib::Dispatcher を使う。

Glib::Dispatcher::connect()でスロット関数とコネクトして Glib::Dispatcher::emit()で メインスレッド内でコネクトした関数を実行する。

ソース

disp.cpp

#include <gtkmm.h>
#include <iostream>

// gettid
#include <sys/types.h>
#include <linux/unistd.h>
_syscall0(pid_t,gettid)

class MainWin : public Gtk::Window
{
    Glib::Dispatcher m_dispatch;

public:
    MainWin();
    virtual ~MainWin(){}

private:
    void slot_thread();
    void slot_dispatch();
};

MainWin::MainWin()
{
    resize( 100, 100 );
    show_all_children();

    std::cout << "main tid = " << gettid() << std::endl;

    // ディスパッチャとスロットのコネクト
    m_dispatch.connect( sigc::mem_fun( *this, &MainWin::slot_dispatch ) );

    // スレッド起動
    Glib::Thread* thread = Glib::Thread::create( sigc::mem_fun( *this, &MainWin::slot_thread ), false );
}


// スレッド
void MainWin::slot_thread()
{
    std::cout << "slot_thread tid = " << gettid() << std::endl;
    sleep( 2 );
    std::cout << "slot_thread stop(" << gettid() << ")" << std::endl;

    // 直接 slot_dispatch()を呼び出した場合
    slot_dispatch();

    // ディスパッチしてslot_dispatch()を呼び出した場合
    // slot_dispatch()はメインスレッドの中で実行される
    m_dispatch.emit();
}


void MainWin::slot_dispatch()
{
    std::cout << "slot_dispatch tid = " << gettid() << std::endl;
}


int main( int argc, char *argv[] )
{
    // スレッドシステムの初期化
    Glib::thread_init();

    Gtk::Main kit( argc, argv );
    MainWin hw;
    Gtk::Main::run( hw );

    return 0;
}

コンパイル

必要なコンパイルオプションは pkg-config を使って取得する。今回はスレッドを 使用しているので pkg-config --libs gthread-2.0 の指定も必要である。

g++ disp.cpp -o disp `pkg-config gtkmm-2.4 --cflags --libs` `pkg-config --libs gthread-2.0`

結果

slot_dispatch()のtidに注目する。同じ関数でも異なるスレッドで実行されている ことがわかる。
main tid = 11982
slot_thread tid = 11983
slot_thread stop(11983)
slot_dispatch tid = 11983
slot_dispatch tid = 11982