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を作れてしまう点にある。&RcRc: Sync(=&Rc: Send)によって複数のスレッドにちらばっている状態で、同時にcloneされうる。これではnon-atomicなカウントを複数のスレッドから同時に書き換えることになるのでダメ。一方ArcSyncになりうる。
  • Send: 複数のスレッドにshared ownershipを与えるのではなく、ただexclusive ownershipを移すだけ。ここでSendを与えたとすると、Syncのとき同様に、Send + Cloneによって複数のスレッドにちらばっている状態で、同時にdrop, cloneされうる。これではnon-atomicなカウントを複数のスレッドから同時に書き換えることになるのでダメ。一方カウンタをatomicにさえしてしまえば、複数のdropを順序よく扱えるのでArcSendになりうる。

よってSend, Syncではない。具体的な実装を盛り込めないmarkerである Send, Syncの役割を、具体的な実装で書ける(参照カウンタを上げ下げできる)CloneDropで肩代わりしているとも言える。

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 a T 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 be UniqueThreadSafe.
  • T: Sync means it’s safe for many threads to access a T 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 be SharedThreadSafe.

https://nyanpasu64.github.io/blog/an-unsafe-tour-of-rust-s-send-and-sync/ ちとよくわからん

Backlinks