Как Вы эффективно отлаживаете проблемы подсчета ссылок в общей памяти?

Предположите, что у Вас есть ссылка считаемый объект в общей памяти. Подсчет ссылок представляет количество процессов с помощью объекта, и процессы ответственны за постепенное увеличение и постепенное уменьшение количества с помощью атомарных инструкций, таким образом, сам подсчет ссылок находится в общей памяти также (это могло быть поле объекта, или объект мог содержать указатель на количество, я открыт для предложений, если они помогают с решением этой проблемы). Иногда, процесс будет иметь ошибку, которая препятствует тому, чтобы он постепенно уменьшил количество. Как Вы делаете максимально легким выяснить, какой процесс, разве постепенно уменьшающийся, не является количеством?

Одно решение, о котором я думал, дает каждому процессу UID (возможно, их PID). Затем, когда декремент процессов, они продвигают свой UID на связанный список, сохраненный вместе с подсчетом ссылок (я выбрал связанный список, потому что можно атомарно добавить для заголовка с CAS). Когда Вы хотите отладить, у Вас есть специальный процесс, который смотрит на связанные списки объектов, все еще живых в общей памяти, и какой бы ни UIDs приложений не находятся в списке, те, которые должны все же постепенно уменьшить количество.

Недостаток к этому решению - то, что оно имеет O (N) использование памяти, где N является количеством процессов. Если количество процессов с помощью области общей памяти является большим, и у Вас есть большое количество объектов, это быстро становится очень дорогим. Я подозреваю, что могло бы быть промежуточное решение, где с частичной информацией о фиксированном размере Вы могли помочь отладке так или иначе способностью сузить список возможных процессов, даже если Вы не могли бы точно определить единственный. Или если Вы могли бы просто обнаружить, какой процесс не постепенно уменьшился, когда только единственный процесс не имеет (т.е. не могущий обработать обнаружение 2 или больше процессов, не удающихся постепенно уменьшать количество), который, вероятно, все еще был бы большой справкой.

(Существуют более 'человеческие' решения этой проблемы, как проверка, что все приложения пользуются той же библиотекой для доступа к региону общей памяти, но если общую область рассматривают как двоичный интерфейс, и не все процессы будут приложениями, записанными Вами, это находится вне Вашего контроля. Кроме того, даже если все приложения пользуются той же библиотекой, одно приложение могло бы иметь ошибку за пределами библиотеки, повреждающей память таким способом, которым этому препятствуют постепенно уменьшить количество. Да я использую небезопасный язык как C/C++ ;)

Править: В единственных ситуациях с процессом Вы будете иметь контроль, таким образом, можно будет использовать RAII (в C++).

5
задан Joseph Garvin 8 February 2010 в 08:48
поделиться

5 ответов

Вы можете сделать это, используя только одно дополнительное целое число на объект.

Инициализируйте целое число нулем. Когда процесс увеличивает счетчик ссылок для объекта, он XORs его PID в целое число:

object.tracker ^= self.pid;

Когда процесс уменьшает счетчик ссылок, он делает то же самое.

Если счетчик ссылок когда-либо останется равным 1, то целое число трекера будет равно PID процесса, который увеличил его, но не уменьшил.


Это работает, потому что XOR коммутативен ( (A ^ B) ^ C == A ^ (B ^ C) ), поэтому если процесс XORит трекер со своим собственным PID четное число раз, это то же самое, что XORить его с PID ^ PID - это ноль, что оставляет значение трекера незатронутым.

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

7
ответ дан 14 December 2019 в 01:07
поделиться

По сути, общее состояние разделяемой памяти не является надежным решением, и я не знаю способа делая его надежным.

В конечном итоге, если процесс завершается, все его неразделенные ресурсы очищаются операционной системой. Кстати, это большой выигрыш от использования процессов (fork ()) вместо потоков.

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

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

Я рекомендую использовать каналы или другие примитивы передачи сообщений между каждым процессом ( иногда возникают естественные отношения господина и раба, иногда всем нужно говорить со всеми). Затем вы пользуетесь преимуществом того, что операционная система закрывает эти соединения, когда процесс умирает, и ваши партнеры получают сигнал в этом случае. Кроме того, вы можете использовать сообщения о тайм-ауте ping / pong, чтобы определить, завис ли одноранговый узел.

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

1
ответ дан 14 December 2019 в 01:07
поделиться

Нужны ли какие-либо дополнительные аргументы, чтобы указать, что он компилируется для DLL? (Я знаю, что DLL экспортированные прототипы нуждаются __ declspec (dllexport)).

Нет с тех пор, как Win3x ушел, теперь вам просто нужно либо __ declspec (dllexport) или .DEF файл, который определяет имена символов, которые вы хотите экспортировать. файл .def позволяет экспортировать символы с измененными именами, поэтому он может быть полезен в особых случаях.

Я знаю, что в качестве аргумента требуется ссылке.

Да.

Буду ли я запускать lib и ссылку, чтобы создать .lib и .dll соответственно, или ссылка буду производить оба?

lib используется только для создания статических библиотек (или для добавления .objs в ваш implib) Ссылка создаст для нее как .dll, так и import .lib.

-121--1307050-

Я бы поместил его в папку программы, добавил ссылку в папку "Меню" Пуск ", чтобы разрешить прямой доступ (без запуска инструмента), и просто на некоторое событие щелчка System.Diagnostics.Process.Start (@. "\Manual.pdf");

Обновить

Ок, теперь мы пришли к полностью Как встроить файл в мое приложение и запустить его?

Для этого вопроса вы найдете уже несколько ответов здесь, но вот краткая версия:

  1. Щелкните правой кнопкой мыши проект и выберите Add - Existing пункт
  2. Выберите файл ( не нажимайте его дважды )
    • Нажмите маленькую стрелку рядом с кнопкой Add и выберите Add As Link
  3. Дважды щелкните на свойствах - Щелчок Resources.resx
  4. небольшая стрела рядом с Добавляет Ресурс и избранный, Добавляет Существующий Файл
  5. , Избранный тот же файл снова в открытом диалоге
  6. Теперь, вы можете получить доступ к файлу в рамках своего кодекса как байт [] от Свойства. Ресурсы. NameOfResource

С этими шагами, вы ссылаетесь на свой файл, где когда-либо он существует в вашей структуре. Если вам нравится, что копия файла pdf будет помещена в подпапку Resources в рамках проекта, просто пропустите одну и две точки в приведенном выше списке.

Чтобы открыть файл pdf, необходимо записать байт [] на диск (возможно, с помощью Path.GetTempFileName () ) и запустить его с Adobe Reader. (Не забудьте удалить файл после использования)

-121--1549520-

Наиболее эффективные системы отслеживания для владения ресурсами даже не используют счетчики ссылок, не говоря уже о списках держателей ссылок. Они просто имеют статическую информацию о макетах каждого типа данных, которые могут существовать в памяти, а также форму кадра стека для каждой функции, и каждый объект имеет индикатор типа. Таким образом, инструмент отладки может сканировать стек каждого потока и следовать ссылкам на объекты рекурсивно, пока он не будет иметь карту всех объектов в памяти и как они ссылаются друг на друга. Но, конечно, системы, которые имеют эту возможность, также имеют автоматический сбор мусора в любом случае. Им нужна помощь компилятора, чтобы получить всю эту информацию о раскладке объектов и стековых кадров, и такая информация фактически не может быть достоверно получена из C/C + + во всех случаях (поскольку ссылки на объекты могут храниться в объединениях и т.д.) Со стороны плюса они выполняют путь лучше, чем отсчет ссылок во время выполнения.

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

Это означает, что вам не нужно указывать часть вопроса «несколько процессов, общая память». Вы сталкиваетесь с той же проблемой, с которой сталкиваются все, когда они пытаются использовать подсчет ссылок. Те, кто использует потоки (или свободно использует общую память; то же самое) сталкиваются с другим набором проблем. Соберите их вместе, и у вас будет мир боли.

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

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

Локальные сокеты представляют собой очень кросс-платформенный и очень быстрый API для межпроцессной связи; единственная, которая в основном одинаково работает во всех Унисах и Windows. Поэтому рассмотрите возможность использования этого в качестве минимального канала связи.

Кстати, используете ли вы последовательно интеллектуальные указатели в процессах, содержащих ссылки? Это твоя единственная надежда получить справочный счет даже наполовину правильно.

1
ответ дан 14 December 2019 в 01:07
поделиться

Используйте следующее

int pids[MAX_PROCS]
int counter;

Приращение

do
   find i such pid[i]=0  // optimistic
while(cas[pids[i],0,mypid)==false)
my_pos = i;
atomic_inc(counter)

Декремент

pids[my_pos]=0
atomic_dec(counter);

Чтобы вы знали все процессы, использующие этот объект

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

0
ответ дан 14 December 2019 в 01:07
поделиться

Я использую этот код, чтобы успешно выполнить то, что вы пытаетесь:

private void insertNowButton_Click(object sender, RoutedEventArgs e)
{
    //NOTE:  The caret position does not change.
    richTextBox1.CaretPosition.InsertTextInRun(DateTime.Now.ToString());
}

EDIT: Addressing Update 1

private void DateTimeStampButton_Click(object sender, RoutedEventArgs e)
{
    var tr = new TextRange(textBox.Document.ContentStart, textBox.Document.ContentEnd);

    if (tr.Text.Length == 2)
    {
        if (tr.Text == "\r\n")
        {
            tr.Text = tr.Text.TrimStart(new[] { '\r', '\n' });
        }
    }

    /* Changing the text is the only way I can get the date to insert at the beginning */
    tr.Text = "I need a beer at ";

    textBox.CaretPosition.InsertTextInRun(DateTime.Now.ToString());
}

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

-121--4167038-

Можно начать с плагина Местоположение учетной записи DHH , но изменить его, чтобы использовать доменное имя верхнего уровня (TLD) вместо поддомена. Это очень простая библиотека, но она выполняет работу. Убедитесь, что все ваши находки в приложении представлены учетной записью , связанной с именем домена.

-121--4321014-

Далее, чтобы сделать вещи самостоятельно: вы также можете использовать некоторые инструменты, как AQTime, который имеет эталонный подсчитанный memchecker.

0
ответ дан 14 December 2019 в 01:07
поделиться
Другие вопросы по тегам:

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