RcはSend, Syncではない
nomicon:
- A type is Send if it is safe to send it to another thread.
- A type is Sync if it is safe to share between threads (T is Sync if and only if
&T
is Send).
Rc
はatomicではないカウンタを持っている。このとき、
Sync
:- 惜しい「
&Rc
として勝手にシェアされると参照カウンタを上げ下げできないのでダメ」…通常borrowを渡す分には問題ない。そのborrowがdropされるとしても、もとのRc
にはなんら影響がないからだ。参照カウンタの「参照」はborrowを指すのではない(borrowはコンパイル時にチェックされるが、Rcはそれを動的にやるためのもの)。 - 問題は
&Rc
をcloneしてRc
を作れてしまう点にある。&Rc
がRc: Sync
(=&Rc: Send
)によって複数のスレッドにちらばっている状態で、同時にcloneされうる。これではnon-atomicなカウントを複数のスレッドから同時に書き換えることになるのでダメ。一方Arc
はSync
になりうる。
- 惜しい「
Send
: 複数のスレッドにshared ownershipを与えるのではなく、ただexclusive ownershipを移すだけ。ここでSend
を与えたとすると、Sync
のとき同様に、Send + Clone
によって複数のスレッドにちらばっている状態で、同時にdrop, cloneされうる。これではnon-atomicなカウントを複数のスレッドから同時に書き換えることになるのでダメ。一方カウンタをatomicにさえしてしまえば、複数のdrop
を順序よく扱えるのでArc
はSend
になりうる。
よってSend, Sync
ではない。具体的な実装を盛り込めないmarkerである Send, Sync
の役割を、具体的な実装で書ける(参照カウンタを上げ下げできる)Clone
とDrop
で肩代わりしているとも言える。
std::marker::Send,Sync のofficial docsとNomiconと以下を見比べるのがよさそう。
https://stackoverflow.com/questions/59428096/understanding-the-send-trait
https://limpet.net/mbrubeck/2019/02/07/rust-a-unique-perspective.html より:
T: Send
means it’s safe to access aT
on a single other thread, where one thread at a time has exclusive access. A value of this type can be moved to another thread by unique ownership, or borrowed on another thread by unique reference (&mut T
). A more descriptive name for this trait might beUniqueThreadSafe
.T: Sync
means it’s safe for many threads to access aT
simultaneously, with each thread having shared access. Values of such types can be accessed on other threads via shared ownership or shared references (&T
). A more descriptive name would beSharedThreadSafe
.
https://nyanpasu64.github.io/blog/an-unsafe-tour-of-rust-s-send-and-sync/ ちとよくわからん