Open pingzhaozz opened 10 months ago
It's not clear to me what use case this is trying to solve. The most common use case for RwLock is to have many readers but few writers. Your implementation does not help with this case since all the readers are still thrashing read_state
.
Have you considered a different implementation using a sharded RwLock? The basic idea is to have an array of [CachePadded<RawRwLock>; N]
and assign readers to one of the locks depending on its thread ID. This is optimized for read performance: writers will need to acquire a write lock on all the locks in the array before being able to grant write access.
Original RwLock memory layout likes this:
pub struct RwLock<T: ?Sized> {
raw: RawRwLock,
data: UnsafeCell<T>,
}
raw
and data
share the same cache-line. In multi read locks, raw
change will cause false sharing with data
since the data
doesn't change in read, only the read state changes. SegRwLock
separate read
cache-line and write + data
cache-line, which memory layout looks like:
pub struct SegRwLock<T: ?Sized> {
read: ReadLock,
padded: <CachePadded>
write: WriteLock,
data: UnsafeCell<T>,
}
One matter need to care is that repr(align(n))
doesn't work inside the struct. So manually added the pad.
Add a new RwLock type as SegRwLock which separate the cache line for Read state and Write state in RwLock to solve the cache-line false sharing problem in RwLock in multi threads scenarios.
Since the 'Data' protected by RwLock shares the same cache-line with lock state. When lock state changes the whole cache-line need update which is not necessary for 'Data' in Read lock, and cause unnecessary cache-line update. SegRwLock put Read state in one cache-line and Write state and 'Data' in the other cache-line, to avoid the false sharing between Read state and 'Data'.