glib g主循环回调在没有理由的情况下被多次调用

时间:2017-11-13 16:56:35

标签: c glib

我希望有一个进程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;
}

1 个答案:

答案 0 :(得分:1)

只要文件可供阅读,打开文件并创建频道就会触发回调。

在Linux中,您需要使用inotify观察器来实现您想要的效果。以下是帮助您理解它的代码段。在回调方法中,您需要读取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;
}