Как установить указатель на память в NULL, используя memset? - PullRequest
4 голосов
/ 30 декабря 2008

У меня есть структура

typedef struct my_s {

   int x;
   ...
} my_T;

my_t * p_my_t;

Я хочу установить адрес p_my_t на NULL, и до сих пор вот как я пытался это сделать:

memset (&p_my_t, 0, sizeof(my_t*))

Это не выглядит мне правильно, хотя. Как правильно это сделать?


Поправка к вопросу - задать радикально более сложный вопрос :

Вот что я пытаюсь сделать:

  • Два процесса, А и В
  • malloc p_my_t в A, B имеет N потоков и может получить к нему доступ
  • Начните удаление в A, но я не могу просто освободить его, поскольку потоки в B все еще могут его использовать.
  • Итак, я вызываю функцию, передавая адрес p_my_t в B, чтобы установить для его адреса значение NULL в B, чтобы другие потоки в B больше не могли использовать
  • После обратного звонка из B я освобождаю память в A

Примечание: стандартного способа управления распределением памяти между процессами не существует. Вам нужно будет довольно тщательно подумать о том, что происходит.

Ответы [ 9 ]

20 голосов
/ 30 декабря 2008

Не используйте memset для инициализации нулевого указателя, так как это установит в памяти все биты ноль, что не обязательно является представлением нулевого указателя, просто сделайте это:

p_my_t = NULL;

или эквивалент:

p_my_t = 0;
4 голосов
/ 30 декабря 2008

Что именно вы пытаетесь сделать? p_my_t уже указатель, но вы не выделили для него память. Если вы хотите установить указатель на NULL, просто выполните

p_my_t = NULL;

Попытка разыменования этого указателя приведет к ошибке сегментации (или нарушению доступа в Windows).

Как только указатель действительно на что-то указывает (например, через malloc() или назначая ему адрес struct my_T), вы можете memset() it:

memset(p_my_t, 0, sizeof(struct my_T));

Это обнулит всю структуру, обнуляя все поля.

2 голосов
/ 30 декабря 2008

Я думаю, может быть, вы хотите

extern void set_t_pointer_to_null(my_T *pp);

и звоните

set_t_pointer_to_null(&p_my_t);

где

void set_t_pointer_to_null(my_T *pp) { *pp = NULL; }

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

2 голосов
/ 30 декабря 2008

Рекомендуемый код для установки указателя на ноль - присвоение 0 (ноль). Бьярне Страуструп делает это :) В любом случае, он так же выразителен, как и NULL, и не зависит от определения макроса.

Обратите внимание, что NULL не является ключевым словом, оно не зарезервировано, и хотя переопределение может привести к путанице, ничто не говорит о том, что вы не должны (больше, чем стиль). Коллега часто шутит о том, что в каком-то заголовке NULL может отличаться от 0, чтобы посмотреть, как ведет себя код других людей.

В следующем стандарте будет более выразительное ключевое слово nullptr для идентификации нулевого указателя.

0 голосов
/ 30 декабря 2008

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

  • Распределить структуру в разделяемой памяти.
  • Выделите ptr для структуры в разделяемой памяти.
  • Защитите доступ к ptr структуре с помощью блокировки чтения / записи.
  • Процесс A должен получить блокировку WRITE для ptr при инициализации или аннулировании ptr и структуры.
  • Процесс B должен получить блокировку READ для ptr и проверить правильность ptr перед использованием структуры
0 голосов
/ 30 декабря 2008

Если я правильно понял, memset не решит вашу проблему. Если A и B являются отдельными процессами, то p_my_t в процессе A будет отличаться от p_my_t в процессе B. Вы просто не можете передать указатель между различными процессами. Я полагаю, что вы используете какой-то механизм IPC, чтобы синхронизировать два ваших процесса (например, очереди сообщений) и просто использовать p_my_t = NULL вместо memset.

0 голосов
/ 30 декабря 2008

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

0 голосов
/ 30 декабря 2008

За ваш ответ (в другом месте в этом посте) с указанием:

Спасибо, вот что я пытаюсь сделать

  • два процесса, А и В
  • malloc p_my_t в A, B имеет N потоков и может получить к нему доступ
  • начать удаление в A, но я не могу просто освободить его, поскольку потоки в B все еще могут использовать.
  • поэтому я вызываю функцию, передавая адрес p_my_t в B, чтобы установить его адрес на NULL в B, чтобы другие потоки в B больше не могли использовать
  • После обратного звонка из B я освобождаю память в A

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

Обычно я бы рекомендовал использовать класс общего указателя (например, класс shared_ptr Boost), но я не уверен, насколько хорошо это будет работать в этом сценарии. Возможно, вы захотите настроить свой класс так, чтобы он отслеживал свои собственные ссылки и мог использоваться с классом Boost intrusive_ptr.

Таким образом, процесс A может просто забыть об объекте, и когда процесс B завершится, экземпляр my_T узнает, что больше нет ссылок, и очистит себя.

Синхронизация вступает в действие здесь, когда my_T добавляет или удаляет ссылки внутри (поэтому вы не сталкиваетесь с неприятными условиями гонки, когда вам кажется, что она должна себя очистить, но она все еще используется).

Еще один подход, который имеет немного больше смысла "kluge", состоит в том, чтобы присвоить каждому экземпляру my_T флаг "is-valid", чтобы все использующие его процессы / потоки знали, продолжать или нет при этом.

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

0 голосов
/ 30 декабря 2008

Спасибо, вот что я пытаюсь сделать

  • два процесса, А и В
  • malloc p_my_t в A, B имеет N потоков и может получить к нему доступ
  • начать удаление в A, но я не могу просто освободить его, поскольку потоки в B все еще могут использовать.
  • поэтому я вызываю функцию, передаю адрес p_my_t в B, чтобы установить его адрес на NULL в B, чтобы другие потоки в B больше не могли использовать
  • После обратного звонка из B я освобождаю память в A
...