Тип атомарного счетчика ссылок (Arc) - это интеллектуальный указатель, который позволяет вам обмениваться неизменяемыми данными между потоками потокобезопасным способом. Мне не удалось найти хороших статей, объясняющих, как это работает, поэтому я попытаюсь сделать это здесь. Первый раздел - это введение в то, как и зачем использовать Arc; если вы уже знаете это и просто хотите узнать, как это работает, перейдите ко второму разделу под названием; "Как это работает".

Зачем вам нужно использовать Arc?

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

Этот код не компилируется; Мы получим ошибку о том, что ссылка на foo переживет сам foo. Это связано с тем, что foo удаляется в конце основной функции, а затем сброшенное значение будет пытаться получить доступ через 20 миллисекунд в порожденном потоке. Здесь на помощь приходит Arc. Счетчик атомарных ссылок по существу гарантирует, что тип foo не будет удален до тех пор, пока все ссылки на него не прекратятся - так что даже после разрешения основной функции foo все еще будет существовать. Теперь рассмотрим этот пример;

В этом примере мы теперь можем ссылаться на foo в потоке, а также получать доступ к его значению после того, как поток был порожден.

Как это работает?

Теперь вы знаете, как использовать Arc, давайте поговорим о том, как это работает. Когда вы вызываете let foo = Arc :: new (vec! [0]), вы создаете значение vec! [0], атомарный счетчик со значением 1 и сохраняете оба значения в одном месте в куче. Указатель на эти данные в куче затем сохраняется в foo. Итак, foo теперь состоит из указателя на объект, который содержит vec! [0] и atomic_counter.

Когда вы вызываете let bar = Arc :: clone (& foo), вы берете ссылку на foo, разыменовываете foo (который является указателем на данные в куче, помните), затем переходите по адресу, на который указывает foo, находя значений (это vec! [0] и atomic_counter), увеличивая атомарный счетчик на единицу и затем сохраняя адрес, который указывает на vec! [0] в bar.

Когда foo или bar выпадают из области видимости и, следовательно, вызывается Arc :: drop (), atomic_counter уменьшается на единицу. Если Arc :: drop () обнаруживает, что атомарный счетчик равен 0, то данные, на которые он указывает в куче (vec! [0] и atomic_counter), очищаются и удаляются из кучи.

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

Важно отметить, что Arc может содержать только неизменяемые данные. Это связано с тем, что Arc не может гарантировать безопасность от гонок данных, если два потока попытаются изменить значение, содержащееся внутри, в одно и то же время. Если вы хотите изменить данные, вам следует инкапсулировать защиту Mutex внутри типа Arc.

Так почему же эти вещи делают Arc thread безопасным?

Arc является потокобезопасным, потому что он гарантирует компилятору, что ссылка на данные будет существовать по крайней мере столько же, сколько и сами данные. Это связано с тем, что каждый раз, когда вы создаете новую ссылку на данные в куче, атомарный счетчик увеличивается на единицу, и данные удаляются только в том случае, если атомарный счетчик равен нулю (с уменьшениями, происходящими каждый раз, когда ссылка выпадает из scope) - разница между Arc и обычным Rc (счетчик ссылок) заключается только в атомном счетчике.

Так в чем же смысл Rc и почему бы не использовать Arc для всего?

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