Добавьте fds в главное окно GLIB

#c #linux #multithreading #gtk3 #glib

Вопрос:

Мне нужно прикрепить файловые дескрипторы к главному интерфейсу GLIB. Моя проблема в том, что список файловых дескрипторов не фиксируется во время выполнения.

Согласно документации GLIB, я могу:

  • создайте GIOChannel для каждого FD с помощью g_io_channel_unix_new и прикрепите его к контексту с помощью g_io_add_watch
  • Используйте Gsource, созданный с помощью g_io_create_watch, и установите обратный вызов g_source_set_callback

Мой вопрос : возможно ли динамически изменять источник или контекст. И как я могу это сделать ? Я нахожу способность GSourceFuncs, но это не соответствует моей проблеме.

Спасибо за вашу помощь.

Ответ №1:

g_io_add_watch возвращает идентификатор источника события, который позже можно будет использовать для повторного динамического удаления часов с помощью g_source_remove . Используйте один источник событий для каждого FD и вместо изменения существующих часов удалите старые и создайте соответствующие новые.

Комментарии:

1. Спасибо. Но в какой части кода я должен реализовать функцию удаления/добавления ? Потому что, если я работаю с GIOChannel, у меня есть только основной и обратный вызовы.

2. Это зависит от вашего кода. Поскольку вы не знаете, куда его добавить, правильно ли я предполагаю, что у вас нет контроля над списком? (Если да, то ответ заключается в том, что вы должны добавлять код везде, где вы изменяете список.) Не могли бы вы расширить свой вопрос с некоторой предысторией?

Ответ №2:

Я еще немного покопался в ГЛЕБЕ, и теперь:

  • Я создаю источник с функциями обратного вызова (подготовка, проверка, отправка, завершение).
  • В процессе подготовки обратного вызова FD удаляются с помощью g_source_remove_unix_fd (), а затем добавляются в текущий источник с помощью g_source_add_unix_fd().
  • Я вернул значение FALSE, чтобы установить время ожидания (1 с для моего примера)

Моя проблема в том, что без FD обратный вызов подготовки вызывается каждые 1 сек, как и ожидалось. При добавлении FD обратный вызов подготовки вызывается без тайм-аута. опросы выходят напрямую.

Я заглянул в исходный код GLIB, но не понимаю, почему ?

Помогите пожалуйста С уважением

Ответ №3:

ответ аменофика — самый лучший.

Если вы хотите, чтобы ваш код работал со старым glib, вы можете использовать:

  • g_source_add_poll()
  • g_source_remove_poll()

Ответ №4:

Вы читали документацию по Основному циклу событий? В разделе описания есть довольно хорошее объяснение того, как все работает.

Вы смотрели учебник по пользовательскому источнику GSource? Это позволяет расширить объект GSource, включив в него ваше собственное состояние. Вы также можете написать свои собственные функции подготовки, отправки, запроса и проверки.

Всякий раз, когда я действительно хочу увидеть, как что-то должно быть сделано с GLib, GTK и т. Д., Первое, на что я обращаю внимание, — это тестовый код, который находится в их репозитории git. Обязательно проверьте правильный тег для версии, на которую вы ориентируетесь.

Например, в настоящее время я нацелен на 2.48.2

Вот два довольно хороших примера https://gitlab.gnome.org/GNOME/glib/blob/2.48.2/tests/mainloop-test.c
https://gitlab.gnome.org/GNOME/glib/blob/2.48.2/glib/tests/mainloop.c

Другая приятная особенность заключается в том, что это репозиторий git, поэтому вы можете очень легко его искать.

Ответ №5:

Кажется, я нашел миниатюрный крючок. Попробуйте это:

 struct source {
    GSource gsrc;
    GPollFD *gpfd;
};

struct data {
    /* A something data. */
};

static gboolean gsrc_dispatch(GSource *gsrc, GSourceFunc cb, gpointer data);
static struct data * data_alloc(void);

static GSourceFuncs gsf = {
    .prepare = NULL,
    .check = NULL,
    .dispatch = gsrc_dispatch,
    .finalize = NULL
};

int main(void)
{
    struct source *src;
    int fd;
    struct data *data = data_alloc();

    /* Something other. */

    /* For example, we are want to capture video from a camera. */
    fd = open("/dev/video0", O_RDWR);
    if (fd < 0) {
        perror("open()");

        return -1;
    }

    src = (struct source *) g_source_new(amp;gsf, sizeof(struct source));
    src->gpfd = g_source_add_unix_fd((GSource *) src, fd, G_IO_IN);

    g_source_set_callback((GSource *) src, NULL, data, NULL);
    g_source_attach((GSource *) src, NULL);

    /* Something other and free. */

    return 0;
}

static gboolean
gsrc_dispatch(GSource *gsrc, GSourceFunc cb, gpointer data)
{
    struct source *src = (struct source *) gsrc;
    struct data *d = data;

    if (src->gpfd != NULL) {
        if (src->gpfd->revents amp; G_IO_IN) {
            /* Capture a frame. */
        }
    }

    g_main_context_iteration(NULL, TRUE);

    return G_SOURCE_CONTINUE;
}

static struct data *
data_alloc(void)
{
    /* Allocate a data. */
}
 

Да, вы можете использовать двойной gpfd указатель.