c - флешку - удалить файл linux




Могу ли я сделать memcpy для копирования на запись в Linux? (4)

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

У меня есть код, в котором я часто копирую большой блок памяти, часто после внесения в него только очень небольших изменений.

Я внедрил систему, которая отслеживает изменения, но я подумал, что было бы неплохо, если бы можно было сказать ОС, чтобы сделать «копирование на запись» в памяти, и пусть это имеет дело только с копией этих частей которые меняются. Однако, в то время как Linux делает копию на запись, например, когда fork () ing, я не могу найти способ контролировать это и делать это сам.


Вот рабочий пример:

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define SIZE 4096

int main(void) {
  int fd = shm_open("/tmpmem", O_RDWR | O_CREAT, 0666);
  int r = ftruncate(fd, SIZE);
  printf("fd: %i, r: %i\n", fd, r);
  char *buf = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,
      MAP_SHARED, fd, 0);
  printf("debug 0\n");
  buf[SIZE - 2] = 41;
  buf[SIZE - 1] = 42;
  printf("debug 1\n");

  // don't know why this is needed, or working
  //r = mmap(buf, SIZE, PROT_READ | PROT_WRITE,
  //  MAP_FIXED, fd, 0);
  //printf("r: %i\n", r);

  char *buf2 = mmap(NULL, SIZE, PROT_READ | PROT_WRITE,
    MAP_PRIVATE, fd, 0);
  printf("buf2: %i\n", buf2);
  buf2[SIZE - 1] = 43;
  buf[SIZE - 2] = 40;
  printf("buf[-2]: %i, buf[-1]: %i, buf2[-2]: %i, buf2[-1]: %i\n",
      buf[SIZE - 2],
      buf[SIZE - 1],
      buf2[SIZE - 2],
      buf2[SIZE - 1]);

  unlink(fd);
  return EXIT_SUCCESS;
}

Я немного не уверен, нужно ли мне включить раздел с комментариями для обеспечения безопасности.


Его проще реализовать copy-on-write на объектно-ориентированном языке, например c ++. Например, большинство классов контейнеров в Qt являются копиями на запись.

Но если вы тоже можете это сделать в C, это еще одна работа. Когда вы хотите назначить свои данные новому блоку данных, вы не делаете копии, вместо этого вы просто скопируете указатель в узле обертки вокруг ваших данных. Вам необходимо отслеживать в своих блоках данных статус данных. Если вы сейчас что-то измените в своем новом блоке данных, вы сделаете «реальную» копию и измените статус. Вы, конечно, не можете больше использовать простые операторы типа «=» для назначения, вместо этого должны иметь функции (на C ++ вы просто выполняете перегрузку оператора).

Более надежная реализация должна использовать контрольные счетчики вместо простого флага, я оставлю это вам.

Быстрый и грязный пример: если у вас есть

struct big {
//lots of data
    int data[BIG_NUMBER];
}

вам нужно реализовать функции назначения и getters / seters самостоятельно.

// assume you want to implent cow for a struct big of some kind
// now instead of
struct big a, b;
a = b;
a.data[12345] = 6789;

// you need to use
struct cow_big a,b;
assign(&a, b);   //only pointers get copied
set_some_data(a, 12345, 6789); // now the stuff gets really copied


//the basic implementation could look like 
struct cow_big {
    struct big *data;
    int needs_copy;
}

// shallow copy, only sets a pointer. 
void assign(struct cow_big* dst, struct cow_big src) {
    dst->data = src.data;
    dst->needs_copy = true;
}

// change some data in struct big. if it hasn't made a deep copy yet, do it here.
void set_some_data(struct cow_big* dst, int index, int data } {
    if (dst->needs_copy) {
        struct big* src = dst->data;
        dst->data = malloc(sizeof(big));
        *(dst->data) = src->data;   // now here is the deep copy
       dst->needs_copy = false;
   }
   dst->data[index] = data;
}

Вам также нужно написать конструкторы и деструкторы. Я действительно рекомендую c ++ для этого.


Механизм копирования на запись, используемый, например, fork (), является особенностью MMU (модуля управления памятью), который обрабатывает пейджинг памяти для ядра. Доступ к MMU - это привилегированная операция, т. Е. Не может быть выполнена приложением для пользовательского пространства. Я также не знаю, какой API-адрес для копирования на запись экспортируется в пользовательское пространство.

(Опять же, я не совсем гуру в API Linux, поэтому другие могут указать соответствующие API-вызовы, которые я пропустил.)

Редактировать: И вот, MSalters поднимается к случаю. ;-)







memory-management