仅实现 Send 和 Sync 之一的类型示例有哪些? [英] What are examples of types that implement only one of Send and Sync?
问题描述
为了更好地理解 Send
和 Sync
特征,是否有以下类型的示例:
Just to get better understanding of the Send
and Sync
traits, are there examples of types that either:
- 实现
Send
,不实现Sync
. - 实施
Sync
,不实施Send
.
- Implement
Send
and do not implementSync
. - Implement
Sync
and do not implementSend
.
推荐答案
首先,重要的是要意识到大多数结构(或枚举)都是Send
:
First of all, it is important to realize that most structs (or enums) are Send
:
- 任何不包含任何引用的结构体都可以是
Send + 'static
- 任何包含生命周期下限为
'a
的结构体都可以是Send + 'a
- any struct that does not contain any reference can be
Send + 'static
- any struct that contain references with a lower-bound lifetime of
'a
can beSend + 'a
因此,您通常希望任何 Sync
struct
也是 Send
,因为 Send
是如此容易达到的标准(与 Sync
需要从多个线程安全并发修改的更难的标准相比).
As a result, you would generally expect any Sync
struct
to be Send
too, because Send
is such an easy bar to reach (compared to the much harder bar of being Sync
which requires safe concurrent modification from multiple threads).
但是,没有什么可以阻止类型的创建者将其明确标记为 not Send
.例如,让我们复苏条件!
However, nothing prevents the creator of a type to specifically mark it as not Send
. For example, let's resuscitate conditions!
在 Lisp 中,条件的想法是你为给定的条件设置一个处理程序(比如:FileNotFound
),然后当在堆栈深处时满足这个条件,然后你的处理程序被调用.
The idea of conditions, in Lisp, is that you setup a handler for a given condition (say: FileNotFound
) and then when deep in the stack this condition is met then your handler is called.
您将如何在 Rust 中实现这一点?
How would you implement this in Rust?
好吧,为了保持线程独立性,您可以为条件处理程序使用线程本地存储(请参阅std::thread_local!
).每个条件都是一个堆栈条件处理程序,要么只调用最上面的一个,要么一个从最上面开始一直向下直到成功的迭代过程.
Well, to preserve threads independence, you would use thread-local storage for the condition handlers (see std::thread_local!
). Each condition would be a stack of condition handlers, with either only the top one invoked or an iterative process starting from the top one but reaching down until one succeeds.
但是,您将如何设置它们?
But then, how would you set them?
就我个人而言,我会使用 RAII!我会在线程本地堆栈中绑定条件处理程序并将其注册到框架中(例如,使用侵入式双向链表作为堆栈).
Personally, I'd use RAII! I would bind the condition handler in the thread-local stack and register it in the frame (for example, using an intrusive doubly-linked list as the stack).
这样,当我完成时,条件处理程序会自动取消注册.
This way, when I am done, the condition handler automatically un-registers itself.
当然,系统必须考虑到用户做了意外的事情(比如将条件处理程序存储在堆中,而不是按照创建的顺序删除它们),这就是我们使用双向链表的原因,所以如有必要,处理程序可以从堆栈中间取消注册自己.
Of course, the system has to account for users doing unexpected things (like storing the condition handlers in the heap and not dropping them in the order they were created), and this is why we use a doubly-linked list, so that the handler can un-register itself from the middle of the stack if necessary.
所以我们有一个:
struct ConditionHandler<T> {
handler: T,
prev: Option<*mut ConditionHandler<T>>,
next: Option<*mut ConditionHandler<T>>,
}
并且真正的"处理程序由用户作为 T
传递.
and the "real" handler is passed by the user as T
.
这个处理程序是 Sync
吗?
Would this handler be Sync
?
可能,取决于您如何创建它,但您没有理由无法创建处理程序,因此无法在多个线程之间共享对它的引用.
Possibly, depends how you create it but there is no reason you could not create a handler so that a reference to it could not be shared between multiple threads.
注意:那些线程无法访问其 prev
/next
数据成员,这些数据成员是私有的,不需要 Sync
.
Note: those threads could not access its prev
/next
data members, which are private, and need not be Sync
.
这个处理程序会是Send
吗?
除非特别小心,否则不会.
Unless specific care is taken, no.
prev
和 next
字段不受并发访问保护,更糟糕的是,如果处理程序在另一个线程获得对它的引用时被删除(对于例如,另一个处理程序试图取消注册自己),那么这个悬空引用将导致未定义行为.
The prev
and next
fields are not protected against concurrent accesses, and even worse if the handler were to be dropped while another thread had obtained a reference to it (for example, another handler trying to un-register itself) then this now dangling reference would cause Undefined Behavior.
注意:后一个问题意味着只是将 Option<*mut Handler
切换为 AtomicPtr
不是充足的;请参阅编写无锁算法的常见陷阱更多详情.
Note: the latter issue means that just switching Option<*mut Handler<T>>
for AtomicPtr<ConditionHandler<T>>
is not sufficient; see Common Pitfalls in Writing Lock-Free Algorithms for more details.
你就知道了:ConditionHandler
是 Sync
如果 T
是 Sync
但会永远不要发送
(按原样).
And there you have it: a ConditionHandler<T>
is Sync
if T
is Sync
but will never be Send
(as is).
为了完整性,许多类型实现了 Send
但没有实现 Sync
(大多数 Send
类型,实际上):Option
或 Vec
例如.
For completeness, many types implement Send
but not Sync
(most Send
types, actually): Option
or Vec
for example.
这篇关于仅实现 Send 和 Sync 之一的类型示例有哪些?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!