glib g 主循环回调无故调用多次

glib g main loop callback called more than one time without reason

我想要一个进程 g_main_loop 调用文件描述符中传入字符的回调。

所以我尝试在我的板上使用上面的代码手动创建 /home/dev 文件。

除了启动此代码外,不做任何事情,回调将继续调用。

我不明白为什么。我希望只有在 /home/dev 文件中写入时才会调用回调。是 f_open 文件选项问题吗?还是我没有做正确的事情,文件描述符将数据视为已读?

#include <stdio.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

gboolean cb_1 (GIOChannel *source, GIOCondition condition, gpointer data);

int main(void)
{
  GMainLoop* mainloop;
  int fd;
  GIOChannel* channel;

  mainloop = g_main_loop_new(NULL, TRUE);

  fd=g_open("/home/dev", O_RDONLY, O_NONBLOCK);

  channel=g_io_channel_unix_new(fd);

  g_io_add_watch(channel, G_IO_IN, cb_1, NULL);

  g_main_loop_run(mainloop);

  g_main_loop_unref(mainloop);
}

gboolean cb_1 (GIOChannel *source, GIOCondition condition, gpointer data)
{
  gchar** line=NULL;
  GIOStatus status;
  GError* error;

  printf("cb\n");    

  status=g_io_channel_read_line(source, line, NULL, NULL, &error);

  if(G_IO_STATUS_NORMAL == status)
  {
    printf("callback : data : %s\n", *line);
    g_free(*line);
  }

  return TRUE;
}

打开文件并创建频道将在文件可供读取时触发您的回调。

在Linux中,你需要inotify watchers来实现你想要的。下面是帮助您理解它的代码片段。在回调方法中,您需要阅读 struct inotify_event 以了解调用回调的事件。阅读 inotify 手册页以获取有关您可以使用的可能掩码的完整详细信息。您可能还需要像 IN_CREATE | 这样的标志。 IN_DELETE.

#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include <sys/inotify.h>

GMainLoop *mainloop;

static gboolean inotify_data(GIOChannel * channel, GIOCondition cond, gpointer user_data)
{
     printf("event on GIOChannel\n");
     char buffer[256];
     gsize bytes_read;

     GIOStatus status = g_io_channel_read_chars(channel, buffer, sizeof(buffer) - 1, &bytes_read, NULL);

     /* buffer can have multiple inotify_event structs which contains
      * details of what event, which file triggered this callback.
      */
     return TRUE;
}

int main(void)
{
     int fd, wd;
     GIOChannel *channel;

     mainloop = g_main_loop_new(NULL, FALSE);

     fd = inotify_init();
     if (fd < 0) {
          exit(EXIT_FAILURE);
     }

     wd = inotify_add_watch(fd, "/home/test", IN_OPEN | IN_MODIFY);

    channel = g_io_channel_unix_new(fd);
    if (!channel) {
        close(fd);
        exit(EXIT_FAILURE);
    }
    g_io_channel_set_close_on_unref(channel, TRUE);
    g_io_channel_set_encoding(channel, NULL, NULL);
    g_io_channel_set_buffered(channel, FALSE);

    g_io_add_watch(channel, G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR, inotify_data, NULL);

    g_main_loop_run(mainloop);

    return 0;
}