Изохронная доставка файлов данных в многопроцессорном режиме, используйте select | опрос | Другой? - PullRequest
0 голосов
/ 11 января 2011

У меня есть большой файл данных, который постоянно (и синхронно) добавляется измерительными устройствами в полевых условиях. Мне нужно изохронно доставлять самые последние данные в этот файл на онлайн-панель. Я говорю изохронно, потому что «приборная панель» не заботится о отображении потока данных (ситуация с высокой задержкой), она просто заботится о самых последних точках данных в файле, которые ему отправляют. Я не могу гарантировать, что скорость роста файлов меньше, чем моя эффективная исходящая пропускная способность.

Итак, у меня есть один постоянно добавляемый файл, но у меня есть несколько процессов, которым необходимо регулярно отправлять из него самый последний блок информации. Думаю, что-то вроде свободного паба.

Я могу:

  1. Опросить файл, чтобы увидеть, есть ли рост, затем выполнить поиск в EOF для последнего блока (ов) данных,
  2. select () - стиль и получение уведомлений об упомянутых изменениях, но тогда мне все равно придется искать последний бит данных?
  3. Пусть процесс поместит последний бит данных в разделяемую память для чтения, но у меня не возникнет той же проблемы, которую мне нужно решить в # 1 и # 2, потому что программа записи в разделяемой памяти будет вести себя одинаково.

Любые другие предложения или рекомендации?

1 Ответ

1 голос
/ 12 января 2011

Если я вас правильно понял, вы просто хотите, чтобы панель мониторинга периодически обновлялась последним (текущим) блоком.Тогда простым вариантом будет:

  • sleep (), stat () файл, чтобы увидеть, изменился ли он, отправить данные, если они подходят.можно использовать inotify, чтобы получать уведомления при изменении файла.Таким образом, вы можете избежать ненужных пробуждений предыдущего подхода.Так что эта опция будет:
    • ждать уведомления, если уведомление приходит stat (), если файл изменился, отправьте данные и sleep (), чтобы избежать слишком частых обновлений.* Этот последний может выглядеть примерно так:
      #include <stdio.h>
      #include <stdlib.h>
      #include <errno.h>
      
      #include <unistd.h>
      #include <fcntl.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      
      #include <sys/inotify.h>
      
      
      #define BLOCK_SIZE 5
      
      
      static ssize_t read_fully(int fd, void *buf, size_t count)
      {
          ssize_t ret;
          size_t nread;
      
          nread = 0;
          do {
                  ret = read(fd, buf, count);
                  if (ret > 0)
                          nread += ret;
          } while ((ret > 0 && nread < count) || (ret < 0 && errno == EINTR));
      
          return ret < 0 ? ret : (ssize_t) nread;
      }
      
      static void show_current_block(int fd)
      {
          static off_t size = 0;  /* non-theadsafe, move fd and size to a
                                     context struct passed as an argument
                                     if you want thread-safety            */
          signed char block[BLOCK_SIZE];  /* Assume only ASCII-compatible encoding */
          struct stat st;
          ssize_t ret;
      
          if (fstat(fd, &st) < 0) {
                  perror("fstat");
                  exit(1);
          }
      
          /* Handle truncated file */
          if (st.st_size < size) {
                  size = 0;
          }
      
          if (st.st_size >= size + BLOCK_SIZE) {
                  size = st.st_size / BLOCK_SIZE * BLOCK_SIZE;
      
                  if (lseek(fd, -BLOCK_SIZE, SEEK_END) < 0) {
                          perror("lseek");
                          exit(1);
                  }
      
                  ret = read_fully(fd, block, BLOCK_SIZE);
      
                  if (ret < 0) {
                          perror("read");
                          exit(1);
                  }
      
                  if (ret == 0) {
                          fprintf(stderr, "file closed!");
                          exit(1);
                  }
      
                  /* Assume only ASCII-compatible encoding, don't print
                   * neither C0 control chars, nor > 0x7f chars (including C1)
                   */
                  printf("Current block: %c%c%c%c%c\n",
                          block[0] < 20 ? '.' : block[0],
                          block[1] < 20 ? '.' : block[1],
                          block[2] < 20 ? '.' : block[2],
                          block[3] < 20 ? '.' : block[3],
                          block[4] < 20 ? '.' : block[4]);
      
                  /* Don't update too often */
                  usleep(3000 * 1000);
          }
      }
      
      int main(void)
      {
          int fd, ifd, wd;
          struct inotify_event ev;
          ssize_t ret;
      
          fd = open("testfile", O_RDONLY);
          if (fd < 0) {
                  perror("open");
                  exit(1);
          }
      
          ifd = inotify_init();
          if (ifd < 0) {
                  perror("inotify_init");
                  exit(1);
          }
      
          /* XXX race between open and inotify_add_watch */
          wd = inotify_add_watch(ifd, "testfile", IN_MODIFY);
          if (wd < 0) {
                  perror("inotify_add_watch");
                  exit(1);
          }
      
          show_current_block(fd);
      
          while ((ret = read(ifd, &ev, sizeof(struct inotify_event)))) {
                  if (ret < 0) {
                          perror("read inotify watch");
                          exit(1);
                  }
                  if (ret == 0) {
                          fprintf(stderr, "inotify watch closed!\n");
                          exit(1);
                  }
                  if (ret != sizeof(struct inotify_event)) {
                          fprintf(stderr, "bad inotify event size %d (expected %d)\n",
                                  ret, sizeof(struct inotify_event));
                          exit(1);
                  }
      
                  show_current_block(fd);
          }
      
          return 0;
      }
      
...