Как обновить другие указатели, когда перевыделение перемещает блок памяти?

Ссылка перевыделения говорит:

Функция может переместить блок памяти в новое местоположение, в этом случае новое местоположение возвращается.

Делает это означает это, если я делаю это:

void foo() {

        void* ptr = malloc( 1024 );

        unsigned char* cptr = ( unsigned char* )ptr+256;

        ptr = realloc( ptr, 4096 );
}

затем cptr может стать недопустимым, если перевыделение перемещает блок?

Если да, то перевыделение сигнализирует всегда, что оно переместит блок, так, чтобы я мог сделать что-то, чтобы препятствовать тому, чтобы cptr стал недопустимым?

19
задан Zan Lynx 11 May 2011 в 21:11
поделиться

4 ответа

Для этого можно использовать инструменты, доступные из xdg , в частности xdg-mime query .

Чтобы узнать тип файла, например, файл index.html , необходимо

$ xdg-mime query filetype index.html

Вернуть миметтип. Чтобы узнать, какое приложение связано с этим mimetye, используйте, например,

$ xdg-mime query default text/html

Здесь возвращается epiphany.desktop , т.е. $ APPNAME.desktop , поэтому легко получить из него имя приложения. Если вы просто хотите открыть файл в приложении по умолчанию, вы можете, конечно, просто запустить

$ xdg-open index.html

, что приведет к прозрению.

Функции запроса для ресурсов значков, по-видимому, недоступны в xdg-utils , но можно написать небольшой скрипт python с помощью pyxdg , который также предлагает множество дополнительных функциональных возможностей.

Для привязок C, вероятно, потребуется просмотреть код portland , связанный со страницей xdg .

EDIT:

Что касается libmagic и друзей, вам нужно будет определиться с вашими предпочтениями: хотя libmagic кажется более полным (и точным) с точки зрения охвата типов файлов, совершенно не заботит о приложениях по умолчанию или значках. Он также не предоставляет средства для установки дополнительных миметипов.

-121--1582335-

Позвольте мне задать вопрос: С учетом программного кода (скажем, это однопоточное приложение), каково правильное выполнение? Интуитивно выполнение CPU в порядке указания кода будет правильным . Эта иллюзия последовательного выполнения является тем, что есть у программистов.

Однако современный ЦП не подчиняется такому ограничению. Если не нарушены зависимости (зависимость от данных, управляющая зависимость и зависимость от памяти), ЦП выполняют команды в неупорядоченном режиме. Однако он полностью скрыт для программистов. Программисты никогда не видят, что происходит внутри процессора.

Компиляторы также используют такой факт. Если можно сохранить семантику программы (т.е. присущие вашему коду зависимости), компиляторы переупорядочат любую возможную инструкцию для достижения лучшей производительности. Одной из примечательных оптимизаций является подъем кода: компиляторы могут поднимать команду загрузки, чтобы минимизировать задержку памяти. Но, не волнуйтесь, компиляторы гарантируют его правильность; В любом случае компиляторы НЕ аварийно завершают работу программы из-за такого изменения порядка, так как компиляторы должны сохранять зависимости, по крайней мере. (Но компиляторы могут иметь ошибки: -)

Если вы рассматриваете только однопоточное приложение, вам не нужно беспокоиться о таком неупорядоченном выполнении либо компиляторами, либо ЦП, для однопоточного случая.

(Для получения дополнительной информации рекомендуется ознакомиться с концепцией ILP (параллелизм на уровне инструкций) . Производительность одного потока в основном зависит от того, сколько ILP можно извлечь из одного потока. Таким образом, и ЦП, и компиляторы делают все возможное для повышения производительности.)

при рассмотрении многопоточного выполнения возникает потенциальная проблема согласованности памяти . Интуитивно программисты имеют концепцию последовательной согласованности . Однако современные многоядерные архитектуры выполняют грязную и агрессивную оптимизацию (например, кэши и буферы). Трудно реализовать последовательную согласованность с низкими накладными расходами в современной компьютерной архитектуре. Так, могла возникнуть очень запутанная ситуация из-за неупорядоченных исполнений нагрузок и хранилищ памяти. Можно наблюдать, что некоторые партии и хранилища были выполнены в неупорядоченном состоянии. Прочитайте некоторые статьи, относящиеся к моделям памяти с пониженным энергопотреблением , например модель памяти Intel x86 (см. главу 8, Порядок размещения памяти, тома 3A Руководства разработчика ПО Intel 64 и IA-32 Architectures). Барьеры памяти необходимы в этой ситуации, когда для корректности необходимо обеспечить выполнение инструкций по памяти.

ОТВЕТ НА ВОПРОС : Коротко ответить на этот вопрос непросто. Нет хороших инструментов, которые обнаруживали бы такое неупорядоченное и проблемное поведение из-за модели согласованности памяти (хотя есть исследовательские работы). Короче говоря, вам даже трудно найти такие ошибки в вашем коде. Тем не менее, я настоятельно рекомендую вам прочитать статьи на перепроверенных блокировок и его подробный документ . При перепроверенной блокировке, из-за ослабленной согласованности памяти и переупорядочивания компиляторов (обратите внимание, что компиляторы не знают многопоточного поведения, если не указать явно с барьерами памяти), это может привести к неправильному поведению.

Суммируя:

  • Если вы работаете только над однопоточной программой, то вам не нужно беспокоиться о неупорядоченном поведении.
  • При работе с многоядерными процессорами может потребоваться рассмотреть проблемы согласованности памяти. Но это на самом деле редкость, когда вам действительно нужно беспокоиться о проблеме согласованности памяти. В основном гонки данных , взаимоблокировки и нарушения атомарности убивают многопотоковую программу.
-121--2579277-

Да, cptr становится недопустимым при перемещении блока realloc! И нет, нет никаких упоминаний о том, что сигнализация говорит вам, что она перемещает блок памяти. Кстати, твой код выглядит смешно... читать на... см. мой ответ на другой вопрос и внимательно прочитайте код о том, как он использует realloc . Общий консенсус заключается в том, что если вы сделаете это:

void *ptr = malloc(1024);

/* later on in the code */

ptr = realloc(ptr, 4096);

/* BAM! if realloc failed, your precious memory is stuffed! */

способ обойти это - использовать временный указатель и использовать его, как показано на рисунке:

void *ptr = malloc(1024);

/* later on in the code */

void *tmp = realloc(ptr, 4096);

if (tmp != null) ptr = tmp;

Edit: Спасибо Secure за то, что указал гремлин, который вкрался, когда я печатал это ранее.

7
ответ дан 30 November 2019 в 04:48
поделиться

Да.

Лучше всего сравнить ptr до и после перераспределения и проверить, был ли он перемещен. Не следует назначать указатель на значение смещения, вместо этого следует сохранить смещение и затем индексировать с ним исходный оператор.

т.е.

Вместо void * newPtr = ptr + 10; * newPtr = что-то;

Использовать int new = 10; ptr [new] = нечто;

-121--2218475-

Даже несмотря на то, что вы не любите GLUT. Как это звучит?

Вы можете взглянуть на захват источников GLUT из здесь и изменить его основной цикл. Его можно найти в файле GLUTApplication.m . Вот как это выглядит. Думаю, что вам следует легко извлечь необходимые вызовы GLUT, чтобы поместить их в свой основной цикл.

- (void)run
{
   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   NSRunLoop *runLoop = [[NSRunLoop currentRunLoop] retain];

   [self finishLaunching];
   __glutEnableVisibilityUpdates();
   _running = 1;

   while([self isRunning]) {
      __glutProcessWorkEvents();

      /* Process all pending user events and fire all timers which have
         a fire date before or equal to the current system time. */
      if(__glutIdleFunc || __glutHasWorkEvents()) {
         /* IMPORTANT: This case may _never_ block. */
         [self _runMainLoopUntilDate: _distantPast autoreleasePool: &pool];
         if(__glutIdleFunc) {
            __glutIdleFuncCalled = YES;
            __glutIdleFunc();
         }
      } else {
         /* IMPORTANT: We may either block until the next timer in line is
                       due, or until a new user event arives from the
                       WindowServer. */
         NSDate *limitDate = [runLoop limitDateForMode: NSDefaultRunLoopMode];

         [self _runMainLoopUntilDate: limitDate autoreleasePool: &pool];
      }

      [pool drain];
      pool = [[NSAutoreleasePool alloc] init];
   }
   [runLoop release];
   [pool drain];
}
-121--1906185-

Да, cptr становится недопустимым, если realloc перемещает блок.

2
ответ дан 30 November 2019 в 04:48
поделиться

Да, CPTR станет недействительным, если Realloc перемещает блок.

Нет, нет сигнала. Вам придется проверить возвращаемое значение по сравнению с оригиналом PTR местоположения.

4
ответ дан 30 November 2019 в 04:48
поделиться

Да.

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

I.E.

вместо void * newptr = ptr + 10; * newptr = что-то;

использование int new = 10; ptr [new] = что-то;

3
ответ дан 30 November 2019 в 04:48
поделиться
Другие вопросы по тегам:

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