#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
указатель.