mmap, msync and linux process termination

Под.NET и Visual C++ а именно, у Вас может быть и Неуправляемый и Управляемый код. Термины относятся к способу, которым память выделяется и 'управляется'.

Неуправляемый код был бы материалом C++, к которому Вы привыкли. Динамическое выделение памяти и явное освобождение от памяти. Время выполнения.NET не управляет памятью для Вас, следовательно 'неуправляемый'.

Управляемым кодом, с другой стороны, управляет время выполнения. Вы выделяете память при необходимости (путем объявления переменных, не пространства памяти), и сборщик "мусора" во время выполнения определяет, когда это больше не необходимо и очищает все это. Сборщик "мусора" также переместит память для повышения эффективности. Время выполнения 'управляет' всем этим для Вас.

, Поскольку я упомянул выше, возможно записать код, которым и управляют и неуправляем.

Неуправляемый:

class Bar : public Foo {
    private:
            int fubar;
    public:
            Bar(int i) : fubar(i) {}
            int * getFubar() { return * fubar; }
}

Управляемый:

public ref class Bar :  public Foo
    private:
            int fubar;
    public:
            Bar(int i) : fubar(i) {}
            int ^ getFubar() { return ^ fubar; }
}

Уведомление касательно? Это в значительной степени определяет Управляемый класс. Это становится очень сбивающим с толку при смешивании двух видов кода как бы то ни было. Например, Вы хотите сохранить ссылочный указатель, (^) управляемый эквивалент указателя, к управлению Полем изображения в Вашем неуправляемом классе. Так как сборщик "мусора" может переместить память, в следующий раз, когда Вы пытаетесь разыменовать поле изображения, которым это не может быть найдено. Время выполнения не говорит Ваш неуправляемый код о, это - изменения памяти.

Поэтому необходимо придавить управляемый объект в памяти, чтобы позволить неуправляемому коду отслеживать его. Тогда там распаковывает и все виды других причуд, которые позволяют Вам смешивать два. Сложность кода огромна!

Официально, управляемый/неуправляемый мог бы свестись к способу, которым код выполняется на стопке.NET. Однако, если Вы происходите из среды C++, я надеюсь, что это будет немного более относиться к Вам.

26
задан BD at Rivenhill 10 May 2011 в 16:32
поделиться

5 ответов

Я решил быть менее ленивым и ответить на вопрос о том, записаны ли данные на диск окончательно, написав некоторый код. Ответ в том, что это будет написано.

Вот программа, которая внезапно убивает себя после записи некоторых данных в файл mmap'd:

#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

typedef struct {
  char data[100];
  uint16_t count;
} state_data;

const char *test_data = "test";

int main(int argc, const char *argv[]) {
  int fd = open("test.mm", O_RDWR|O_CREAT|O_TRUNC, (mode_t)0700);
  if (fd < 0) {
    perror("Unable to open file 'test.mm'");
    exit(1);
  }
  size_t data_length = sizeof(state_data);
  if (ftruncate(fd, data_length) < 0) {
    perror("Unable to truncate file 'test.mm'");
    exit(1);
  }
  state_data *data = (state_data *)mmap(NULL, data_length, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_POPULATE, fd, 0);
  if (MAP_FAILED == data) {
    perror("Unable to mmap file 'test.mm'");
    close(fd);
    exit(1);
  }
  memset(data, 0, data_length);
  for (data->count = 0; data->count < 5; ++data->count) {
    data->data[data->count] = test_data[data->count];
  }
  kill(getpid(), 9);
}

Вот программа, которая проверяет полученный файл после смерти предыдущей программы:

#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>

typedef struct {
  char data[100];
  uint16_t count;
} state_data;

const char *test_data = "test";

int main(int argc, const char *argv[]) {
  int fd = open("test.mm", O_RDONLY);
  if (fd < 0) {
    perror("Unable to open file 'test.mm'");
    exit(1);
  }
  size_t data_length = sizeof(state_data);
  state_data *data = (state_data *)mmap(NULL, data_length, PROT_READ, MAP_SHARED|MAP_POPULATE, fd, 0);
  if (MAP_FAILED == data) {
    perror("Unable to mmap file 'test.mm'");
    close(fd);
    exit(1);
  }
  assert(5 == data->count);
  unsigned index;
  for (index = 0; index < 4; ++index) {
    assert(test_data[index] == data->data[index]);
  }
  printf("Validated\n");
}
13
ответ дан 28 November 2019 в 07:12
поделиться

Я нашел комментарий от Линуса Торвальдса, который отвечает на этот вопрос http://www.realworldtech.com/forum/?threadid=113923&curpostid=114068

Отображенные страницы часть кеша файловой системы, что означает, что даже если пользовательский процесс, который внес изменение в эту страницу, умирает, страница все еще управляется ядром, и, поскольку все одновременные обращения к этому файлу будут проходить через ядро, другие процессы будут обслуживаться из этого кэша. В некоторых старых ядрах Linux все было по-другому, поэтому в некоторых документах ядра все еще говорится о принуждении msync.

РЕДАКТИРОВАТЬ: Спасибо, RobH исправил ссылку.

20
ответ дан 28 November 2019 в 07:12
поделиться

Я не нашел очень точного ответа на ваш вопрос, поэтому решил добавить еще один:

  1. Во-первых, о потере данных, используя механизмы write или mmap / memcpy и для записи в кеш страницы, и для синхронизации с нижележащим хранение в фоновом режиме операционной системой на основе настроек замены страницы / алгоритма. Например, в linux есть vm.dirty_writeback_centisecs, который определяет, какие страницы считаются «старыми» для записи на диск. Теперь, даже если ваш процесс умирает после успешного вызова write, данные не будут потеряны, так как данные уже присутствуют на страницах ядра, которые в конечном итоге будут записаны в хранилище. Единственный случай, когда вы потеряете данные, это если сама ОС выйдет из строя (паника ядра, отключение питания и т. Д.). Способом абсолютной проверки того, что ваши данные достигли хранилища, был бы вызов fsync или msync (для mmapped регионов) в зависимости от обстоятельств.
  2. Что касается проблем с загрузкой системы, то да, вызов msync / fsync для каждого запроса резко замедлит вашу пропускную способность, так что делайте это только в случае необходимости. Помните, что вы действительно защищаете от потери данных при сбоях ОС, которые, как я полагаю, встречаются редко, и, вероятно, что-то, с чем можно было бы справиться. Одна из общих оптимизаций заключается в том, чтобы производить синхронизацию через равные промежутки времени, например, 1 секунду, чтобы получить хороший баланс.
5
ответ дан 28 November 2019 в 07:12
поделиться

Я нашел что-то, что добавило к моей путанице:

munmap не влияет на объект, который был отображен, то есть, вызов munmap не приводит к записи содержимого отображаемой области на файл диска . Обновление файла на диске для области MAP_SHARED происходит автоматически с помощью алгоритма виртуальной памяти ядра, когда мы сохраняем данные в отображаемой области памяти.

это выдержка из Расширенное программирование в среде UNIX® .

из справочной страницы linux:

MAP_SHARED Поделитесь этим отображением со всеми другими процессами, которые отображают этот объект. Сохранение в регион эквивалентно записи в файл. Файл не может быть обновлен до тех пор, пока не будут вызваны msync (2) или munmap (2).

оба кажутся противоречивыми. APUE не так?

9
ответ дан 28 November 2019 в 07:12
поделиться

Либо информация о man-страницах Linux неверна, либо Linux ужасно несовместим. msync не должен иметь ничего общего с тем, зафиксированы ли изменения в логическом состоянии файла или же другие изменения, использующие mmap или read для доступа к файлу, видят изменения; это чисто аналог fsync, и его следует рассматривать как неиспользуемый, за исключением целей обеспечения целостности данных в случае сбоя питания или другого сбоя аппаратного уровня.

1
ответ дан 28 November 2019 в 07:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: