Является ли назначение в системах автоматического подсчета ссылок поточно-ориентированным? - PullRequest
0 голосов
/ 07 июня 2018

Такие языки, как Swift, Vala и C ++ (через shared_ptr) управляют памятью путем подсчета ссылок.Насколько мне известно, обновления счетчика ссылок в этих системах выполняются атомарно и, таким образом, потокобезопасны.

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

Так же, как и общие указатели C ++, ссылки Vala, Swiftссылки предпринять шаги, чтобы избежать таких проблем?Если нет, какие шаги необходимы на каждом из трех языков, чтобы сделать такой доступ безопасным?

Любые идеи приветствуются.Спасибо!

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

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

, который оставляет C ++, всегда опаздывая на мяч.

std::shared_ptr Реализация подсчета ссылок является поточно-безопасной,как видно из цитаты в сообщении Алана, но говорить о том, что нужно начинать присматривать за другим объектом, очевидно, нет.

Это не принято делать.Это, скорее, подрывает его назначение, конечно, если вы пытаетесь сделать его более безопасным для работы с кодом.Более подробная информация на cppreference - некоторые из этих перегрузок operator= являются потокобезопасными, а некоторые нет.

0 голосов
/ 07 июня 2018

см. Последний абзац http://en.cppreference.com/w/cpp/memory/shared_ptr

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

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

Например, это небезопасно:

#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <thread>

int main()
{
    std::shared_ptr< std::string > str( new std::string() );
    std::vector< std::thread > threads;
    for ( int i = 0; i < 10; i++ )
    {
        threads.emplace_back([&]
        {
            if ( str->empty() )
            {
                str.reset( new std::string( "thread string" ) );
            }
            else
            {
                str.reset();
            }
        });
    }
    for ( auto& thread : threads )
    {
        thread.join();
    }
}

, но этопотоки не изменяют переменную str, но увеличивают ее счетчик ссылок:

#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <thread>

int main()
{
    std::shared_ptr< std::string > str( new std::string() );
    std::vector< std::thread > threads;
    for ( int i = 0; i < 10; i++ )
    {
        threads.emplace_back([&]
        {
            std::shared_ptr< std::string > str2 = str;
            if ( str2->empty() )
            {
                str2.reset( new std::string( "thread string" ) );
            }
            else
            {
                str2.reset();
            }
        });
    }
    for ( auto& thread : threads )
    {
        thread.join();
    }
}

C ++ 20 добавляет std::atomic_shared_ptr, что полностью поточно-ориентировано.До этого вы можете использовать атомарные функции, не являющиеся членами.

...