Проще говоря, нет.
Условие гонки, согласно которому конечный результат, зависящий от определенного порядка операций, возможно только при подсчете ссылок, операция может сделать объект, который вносит вклад всчитайте от того, который не , то есть, когда у вас есть слабые ссылки .
Вот что считается конечной точкой гонки, является ли ресурс освобожден, потому что пересчет(RC) достигает нуля;вопрос «какая точная операция, выполняемая каким потоком, обнуляет RC», является интересной конечной точкой: неявное предположение об использовании RC для управления ресурсами в многопоточном контексте заключается в том, что любой поток (у которого есть последний владелец) может освободитьресурс.
По определению RC - это сумма отдельных строго положительных вкладов каждого владельца в RC (это 1, так как RC - это количество владельцев, но это не очень важно).В абстрактной настройке RC также может быть формализован как набор владельцев, и целое число будет эффективным представлением необходимой информации из-за особенностей RC:
- каждый владелец знает, чтоон находится в наборе
- владельцы не знают друг друга
- каждый владелец должен увеличить число на некоторое количество (которое по определению равно 1, но может быть любым строго положительным числом), еслидобавляется в набор и уменьшается на ту же сумму, когда он удаляет себя из набора
Таким образом, вы можете представить число как список владельцев, каждый из которых представлен вертикальной линией, как когда детизапоминайте числа (3 = |||
), и только отдельный владелец знает свой собственный бар (вы можете сказать, что все столбцы одинаковые или имеют разные цвета).(Очевидно, что целые числа физически представлены в двоичном виде.)
В установках, где существуют только владельцы (никакая операция не может ссылаться на RC через «слабую ссылку»), есть только две основные операции над множеством владельцев:
- дублировать владельца: сделать нового владельца из владельца
- удалить владельца
Дублирование просто добавляет вертикальную черту.На графическом дисплее вы можете даже разделить полосу, удалив ее середину, оканчивающуюся на две половины полосы.Это расторжение права собственности (как если бы вы продали часть своих акций торгуемой корпорации).
Операция удаления стирает вертикальную черту, принадлежащую владельцу (конечно, на практике нет идентифицированных баров, а небары вообще и его операция уменьшения целого числа, представленного в двоичном виде); если эта операция удалила этот последний столбец , то поток удаления отвечает за освобождение ресурса .
Вы можете легко увидеть, что нулевой RC соответствует пустому наборубары, что происходит после того, как все владельцы отказались от владения.Существует условие гонки, которое определяет точное количество баров в любой момент времени , но это деталь: важно то, что каждый владелец в каждом потоке знает, что он является владельцем.По сути равнодушно к числу других владельцев.(Если бы вы были не равнодушными, вы, вероятно, в первую очередь хотели бы иметь уникальное право собственности, чтобы иметь возможность изменять ресурс без влияния на других пользователей.)
То, что есть условие гонкина множестве подразумевается, что должна использоваться внутренняя атомика (или подобная альтернатива), но владельцам должно быть все равно.Было бы катастрофично, если бы в представлении был случайно удален определенный «бар», это означало бы, что владелец не учитывается, и это был бы владелец зомби: он бы поверил, что он владеет ресурсом, но на самом деле он ничего не будет иметь,Атомарная операция RMW (чтение, запись, изменение) гарантирует невозможность выполнения операции: любой атомарный объект, модифицированный исключительно с помощью операции RMW, не может потерять модификации .
Сама концепция владения подразумевает, что она не может быть создана из ничего: вы можете стать только владельцем чего-то:
- путем создания этой вещи
- или приобретения права собственности (у кого-то) у кого-то, у кого уже есть
Это просто здравый смысл.
Потому что разрушениедоля собственности является необратимой, достижение нулевых владельцев является прекращающим событием;в этот момент гарантируется, что RC никогда больше не будет изменен или даже снова измерен.(Таким образом, владение представлением RC может быть заменено собственностью самого ресурса.)
Эти свойства делают реализацию истинного владения RC очень простой.Это отличается, когда слабые ссылки, то есть RC-only watcher , вводят изображение: инструмент измерения RC обеспечивает гарантию того, что он может производить измерения на RC в любой момент в будущем, независимо от того, будет ли онресурс управляемого пользователя все еще имеет владельца (владельцев), независимо от того, существует ли ресурс пользователя.При слабых ссылках RC может быть прочитан как ноль атомарной операцией, которая не является вертикальной чертой в графическом представлении набора владельцев.Это означает, что время жизни RC становится отличным от времени жизни пользовательского ресурса: сам RC становится другим управляемым ресурсом (внутренним RC).
Слабые ссылки позволяют создавать владельцев без совместного использования существующих прав владения: aслабая ссылка - это (ненадежный) «вариант» будущего владения.Хотя слабые ссылки могут быть созданы только из реальных (то есть сильных) ссылок, что противоречит общим принципам владения.
Так что только со слабыми ссылками, RC может быть длительно нулевым, то есть ноль за небольшим интервалом между последней операцией уменьшения и освобождением самого RC.Использование слабых ссылок означает, что пользовательский код должен быть спроектирован так, чтобы справляться с возможностью нулевого RC, и что в коде MT может быть гонка между потоком, отказывающимся от владения в качестве последнего владельца, и другим потоком, пытающимся воссоздать владение из слабогоссылка.
В реальной жизни традиционные культурные знания бесплатны и могут тиражироваться сколько угодно.Но для традиционных исторических знаний, известных очень немногим людям (например, рецепт семейной кулинарии), лучше сделать копии до того, как умрет последний человек, обладающий этими знаниями: между людьми, умирающими с традиционными знаниями, и людьми, приобретающими традиционное знание, существует раса и передавать эти знания.По сути, это то же самое, что и проблема слабой ссылки / сильной эталонной гонки.
Таким образом, слабые ссылки могут быть полезны для моделирования проблем реального мира, когда наблюдатель не может принудительно сохранить ресурс, если внешний фактор разрушит его, ноМожно наблюдать за эволюцией ресурса, пока он существует.Продвижение слабой ссылки на сильную делает снимок живости ресурса в момент, когда преобразование выполнено, и по своей природе является грубым.
Обратите внимание, что любое значимое использование многих примитивов является грубым внекоторый уровень : вы используете мьютекс, потому что вы не знаете, какому потоку сначала потребуется эксклюзивный доступ к ресурсу;если бы вы знали точный порядок выполнения, вы бы сериализовали потоки и вообще избежали сложности потоков.Гонка за получением доступа к ресурсу не является ошибкой.Только когда правильность выполнения программы зависит от определенного порядка событий, возникает ошибка.
Мы знаем, что приведенный ниже код деструктора должен освободить блок управления, если это последний указатель smart_ptrк управляемому ресурсу.
Да, и это правильно, желаемое поведение, когда срок полезного использования RC заканчивается, когда он достигает нуля, то есть когда реализуется истинное владение и слабые ссылки не поддерживаются.Это не будет правильным для Boost или стандарта shared_ptr
, который поддерживает «слабые» указатели, такие как наблюдатели, не являющиеся владельцами.
Хотя условие гонки, которое вы упомянули в семантически невозможном, есть проблемыздесь:
~smart_ptr() {
if (control_block_ptr->refs.fetch_sub(1, memory_order_acq_rel) == 0) {
delete control_block_ptr;
}
}
Как объяснено, время жизни RC, когда нет чистых наблюдателей (которые не владеют и могут видеть нулевой RC), совпадает с ресурсом управляемого пользователя. Я не вижу выпуска пользовательского ресурса здесь (это может быть где-то еще).
Где сам пользовательский ресурс управляется? Это в деструкторе объекта *control_block_ptr
? Можете ли вы опубликовать немного больше кода, чтобы получить полную картину?
Также вы использовали операцию post -decrement fetch_sub
вместо операции перед декрементом: операции post возвращают предыдущее значение , затем выполняют операцию. С помощью операции post особое интересное значение RC, на которое вы хотите воздействовать, значение до того, как последний владелец перестанет быть владельцем, равно 1, а не 0 .