Под.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++, я надеюсь, что это будет немного более относиться к Вам.
Я решил быть менее ленивым и ответить на вопрос о том, записаны ли данные на диск окончательно, написав некоторый код. Ответ в том, что это будет написано.
Вот программа, которая внезапно убивает себя после записи некоторых данных в файл 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");
}
Я нашел комментарий от Линуса Торвальдса, который отвечает на этот вопрос http://www.realworldtech.com/forum/?threadid=113923&curpostid=114068
Отображенные страницы часть кеша файловой системы, что означает, что даже если пользовательский процесс, который внес изменение в эту страницу, умирает, страница все еще управляется ядром, и, поскольку все одновременные обращения к этому файлу будут проходить через ядро, другие процессы будут обслуживаться из этого кэша. В некоторых старых ядрах Linux все было по-другому, поэтому в некоторых документах ядра все еще говорится о принуждении msync
.
РЕДАКТИРОВАТЬ: Спасибо, RobH исправил ссылку.
Я не нашел очень точного ответа на ваш вопрос, поэтому решил добавить еще один:
Я нашел что-то, что добавило к моей путанице:
munmap не влияет на объект, который был отображен, то есть, вызов munmap не приводит к записи содержимого отображаемой области на файл диска . Обновление файла на диске для области MAP_SHARED происходит автоматически с помощью алгоритма виртуальной памяти ядра, когда мы сохраняем данные в отображаемой области памяти.
это выдержка из Расширенное программирование в среде UNIX® .
из справочной страницы linux:
MAP_SHARED Поделитесь этим отображением со всеми другими процессами, которые отображают этот объект. Сохранение в регион эквивалентно записи в файл. Файл не может быть обновлен до тех пор, пока не будут вызваны msync (2) или munmap (2).
оба кажутся противоречивыми. APUE не так?
Либо информация о man-страницах Linux неверна, либо Linux ужасно несовместим. msync
не должен иметь ничего общего с тем, зафиксированы ли изменения в логическом состоянии файла или же другие изменения, использующие mmap
или read
для доступа к файлу, видят изменения; это чисто аналог fsync
, и его следует рассматривать как неиспользуемый, за исключением целей обеспечения целостности данных в случае сбоя питания или другого сбоя аппаратного уровня.