0

GMainContext の ref_count を適切に減少させることができません。ここでのサンプル プログラムは、大きなプログラムの小さなバージョンです (スレッドを使用するため、コンテキストを作成してスレッドにプッシュする必要があります)。

GMainLoop *loop;
GMainContext *ctx;

struct conn
{
    GSocketClient *client;

    GSocketConnection *conn;
    GInputStream *in;
    GOutputStream *out;

    gchar data[8192];
    unsigned int count;
};

static void
read_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
    struct conn *c = (struct conn *)user_data;
    gssize len = g_input_stream_read_finish(c->in, res, NULL);

    g_input_stream_read_async(c->in, c->data, sizeof c->data / sizeof *c->data, G_PRIORITY_DEFAULT, NULL, read_done_cb, c);
    if (c->count++ == 1) {
        printf("End of life as I know it...\n");
        g_main_loop_quit(loop);
    }
}

static void
write_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
}

static void
connect_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
    printf("## %s\n", __FUNCTION__);

    struct conn *c = (struct conn *)user_data;
    c->conn = g_socket_client_connect_to_host_finish(c->client, res, NULL);

    c->in  = g_io_stream_get_input_stream(G_IO_STREAM(c->conn));
    c->out = g_io_stream_get_output_stream(G_IO_STREAM(c->conn));

    char *data = "GET /axis-cgi/mjpg/video.cgi HTTP/1.0\r\n\r\n";

    g_output_stream_write_async(c->out, data, strlen(data), G_PRIORITY_DEFAULT, NULL, write_done_cb, c);
    g_input_stream_read_async(c->in, c->data, sizeof c->data / sizeof *c->data, G_PRIORITY_DEFAULT, NULL, read_done_cb, c);
}

int
main(int argc, char **argv)
{
    g_type_init();

    struct conn *c = g_malloc0(sizeof *c);
    ctx = g_main_context_new();
    loop = g_main_loop_new(ctx, FALSE);
    g_main_context_push_thread_default(ctx);

    c->client = g_socket_client_new();
    g_socket_client_connect_to_host_async(c->client, "10.85.25.20", 80, NULL, connect_done_cb, c);

    g_main_loop_run(loop);

    g_io_stream_close(G_IO_STREAM(c->conn), NULL, NULL);
    g_object_unref(c->client);
    g_object_unref(c->conn);
    g_main_context_pop_thread_default(ctx);
    g_main_loop_unref(loop);
    g_main_context_unref(ctx);

    return 0;
}

gdb を使用して、return の直前にブレークポイントを挿入すると、ctx にはまだ 1 つの参照カウントがあることがわかります。

(gdb) p ctx->ref_count
 $2 = 1

別のことをすると、g_main_context_unref(ctx);すべてが期待どおりにシャットダウンします。ただし、この所有権をどこで取得するのかわかりません。

よろしくお願いいたします。

4

2 に答える 2

1

エラーが見つかりました。私read_done_cbは別のものを発行g_input_stream_read_asyncし、メインループを終了した直後に発行しました。g_input_stream_read_asyncref_count を増やしましたがGMainLoop、コールバックに戻る機会がありませんでした (および my の ref_count を減らしましたGMainContext)。

g_input_stream_read_asyncコールバックの呼び出しを if ステートメントの下に移動する

static void
read_done_cb(GObject *source_object, GAsyncResult *res, gpointer user_data)
{
    struct conn *c = (struct conn *)user_data;
    gssize len = g_input_stream_read_finish(c->in, res, NULL);

    if (c->count++ == 1) {
        printf("End of life as I know it...\n");
        g_main_loop_quit(loop);
    }

    g_input_stream_read_async(c->in, c->data, sizeof c->data / sizeof *c->data, G_PRIORITY_DEFAULT, NULL, read_done_cb, c);

}

メインコンテキストの参照カウント数を正しく解決しました。

愚かな間違い。うまくいけば、少なくとも誰かが私の投稿の使用法を見つけてくれるでしょう。

于 2012-04-12T18:34:31.337 に答える
0

g_main_context_new()、、g_main_loop_new()およびg_main_context_push_thread_default()すべてがコンテキストを参照します。g_main_context_pop_thread_default()、、g_main_loop_unref()およびg_main_context_unref()すべてがそれを参照解除します。だからあなたの直感は健全です。

gdb:のウォッチポイントを使用しwatch ctx->ref_countて、追加の参照が追加されている場所を見つけます。

于 2012-04-12T10:41:06.893 に答える