7

gtkアプリケーションでは、すべての実行が関数内で行われgtk_mainます。app.execまた、他のグラフィカル フレームワークには、QTClutterclutter_mainのような同様のイベント ループがあります。ただし、 ZeroMQは、挿入されるループがあるという前提に基づいています (例については、ここを参照してください)。while (1) ...

これら 2 つの実行戦略をどのように組み合わせますか?

私は現在、C で記述されたクラッタ アプリケーションで zeromq を使用したいと考えているので、もちろんそれに対する直接的な回答を希望しますが、他のバリアントについても回答を追加してください。

4

5 に答える 5

13

zmq と gtk またはクラッタを組み合わせる適切な方法は、zmq キューのファイル記述子をメイン イベント ループに接続することです。fd は次を使用して取得できます。

int fd;
size_t sizeof_fd = sizeof(fd);
if(zmq_getsockopt(socket, ZMQ_FD, &fd, &sizeof_fd))
      perror("retrieving zmq fd");

それをメイン ループに接続するには、io_add_watch を使用します。

GIOChannel* channel = g_io_channel_unix_new(fd);    
g_io_add_watch(channel, G_IO_IN|G_IO_ERR|G_IO_HUP, callback_func, NULL);

コールバック関数では、読み取る前に、実際に読み取るものがあるかどうかを最初に確認する必要があります。そうしないと、関数が IO の待機をブロックする可能性があります。

gboolean callback_func(GIOChannel *source, GIOCondition condition,gpointer data)
{
    uint32_t status;
    size_t sizeof_status = sizeof(status);   

    while (1){
         if (zmq_getsockopt(socket, ZMQ_EVENTS, &status, &sizeof_status)) {
             perror("retrieving event status");
             return 0; // this just removes the callback, but probably
                       // different error handling should be implemented
         }
         if (status & ZMQ_POLLIN == 0) {
             break;
         }

         // retrieve one message here
    }
    return 1; // keep the callback active
}

注: これは実際にはテストされていません。私が使用している Python+Clutter から翻訳を行いましたが、うまくいくと確信しています。参考までに、実際に動作する完全な Python+Clutter コードを以下に示します。

import sys
from gi.repository import Clutter, GObject
import zmq

def Stage():
    "A Stage with a red spinning rectangle"
    stage = Clutter.Stage()

    stage.set_size(400, 400)
    rect = Clutter.Rectangle()
    color = Clutter.Color()
    color.from_string('red')
    rect.set_color(color)
    rect.set_size(100, 100)
    rect.set_position(150, 150)

    timeline = Clutter.Timeline.new(3000)
    timeline.set_loop(True)

    alpha = Clutter.Alpha.new_full(timeline, Clutter.AnimationMode.EASE_IN_OUT_SINE)
    rotate_behaviour = Clutter.BehaviourRotate.new(
        alpha, 
        Clutter.RotateAxis.Z_AXIS,
        Clutter.RotateDirection.CW,
        0.0, 359.0)
    rotate_behaviour.apply(rect)
    timeline.start()
    stage.add_actor(rect)

    stage.show_all()
    stage.connect('destroy', lambda stage: Clutter.main_quit())
    return stage, rotate_behaviour

def Socket(address):
    ctx = zmq.Context()
    sock = ctx.socket(zmq.SUB)
    sock.setsockopt(zmq.SUBSCRIBE, "")
    sock.connect(address)
    return sock

def zmq_callback(queue, condition, sock):
    print 'zmq_callback', queue, condition, sock

    while sock.getsockopt(zmq.EVENTS) & zmq.POLLIN:
        observed = sock.recv()
        print observed

    return True

def main():
    res, args = Clutter.init(sys.argv)
    if res != Clutter.InitError.SUCCESS:
        return 1

    stage, rotate_behaviour = Stage()

    sock = Socket(sys.argv[2])
    zmq_fd = sock.getsockopt(zmq.FD)
    GObject.io_add_watch(zmq_fd,
                         GObject.IO_IN|GObject.IO_ERR|GObject.IO_HUP,
                         zmq_callback, sock)

    return Clutter.main()

if __name__ == '__main__':
    sys.exit(main())
于 2012-06-02T10:17:34.627 に答える
6

ZeroMQ コードは、できるだけ頻繁に何度も実行したいだけのようです。最も簡単な方法は、ZeroMQ コードをアイドル関数またはタイムアウト関数に配置し、非ブロッキング バージョンの関数が存在する場合はそれを使用することです。

Clutter の場合は、clutter_threads_add_idle()またはを使用しますclutter_threads_add_timeout()。GTK の場合は、g_idle_add()またはを使用しますg_timeout_add()

より難しいが、おそらくより良い方法は、を使用して ZeroMQ コード用の別のスレッドを作成し、提案されているようにブロッキング関数をg_thread_create()使用して構築を使用することです。while(1)それを行う場合、スレッドが互いに通信するための何らかの方法も見つける必要があります.GLibのミューテックスと非同期キューは通常うまくいきます.

于 2011-06-23T11:53:50.467 に答える
2

0MQ ソケット (ZMQ_FD オプション) のファイル記述子を取得し、それをイベント ループに統合できます。gtk にはソケットを処理するための何らかのメカニズムがあると思います。

于 2011-07-27T06:30:03.730 に答える
2

Zeromqtという QT 統合ライブラリがあることがわかりました。ソースを見ると、統合のコアは次のとおりです。

ZmqSocket::ZmqSocket(int type, QObject *parent) : QObject(parent)
{
    ...
    notifier_ = new QSocketNotifier(fd, QSocketNotifier::Read, this);
    connect(notifier_, SIGNAL(activated(int)), this, SLOT(activity()));
}

...

void ZmqSocket::activity()
{
    uint32_t flags;
    size_t size = sizeof(flags);
    if(!getOpt(ZMQ_EVENTS, &flags, &size)) {
        qWarning("Error reading ZMQ_EVENTS in ZMQSocket::activity");
        return;
    }
    if(flags & ZMQ_POLLIN) {
        emit readyRead();
    }
    if(flags & ZMQ_POLLOUT) {
        emit readyWrite();
    }
    ...
}

したがって、QT の統合されたソケット処理に依存しており、Clutter には同様のものはありません。

于 2011-06-23T12:48:44.303 に答える