You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Is it possible to document the preconditions for accessing SeriesBuffer safely across threads? It looks to me that the stored data and the description of the stored data can be updated across threads independently, leaving the risk of them getting out of sync.
In more detail, the number of data points in a SeriesBuffer can be changed independent of the actual points:
even across threads. Put another way, a race on individual struct members is not possible, but a race between them is. With just the right (well, wrong) implementation and execution conditions, the count can be left inaccurate.
It appears that the SeriesBufferGuard is designed to ameliorate this:
as it provides a means to update count while the mutex is locked. This seems reasonable to me (and a clever idea!), provided that count is only updated through the guard. This condition is met in SeriesBufferGuard::extend():
I think that this implementation works in practice due to the drop scope of guard points:
the guard is held until the end of the function
the guard prevents SeriesBufferGuard::extend() from being called (because another SeriesBufferGuard) can not exist
This is implicit behavior, and leaves a foot-gun for future developers if the drop scope is changed:
implSeriesBuffer{fntake(&self) -> (usize,Vec<Series>){let result = self.lock()// <-- lock taken, guard used and immediately dropped.sb.drain().map(/* snip */).collect();let result_count = self// <-- guard no longer exists, SeriesBufferGuard::extend() can be called.count.fetch_update(Ordering::Release,Ordering::Acquire, |_| Some(0)).unwrap();(result_count, result)}}
As this precondition isn't enforced by the type system or hinted at in documentation, I could see a future developer not noticing this pitfall and making this or a similar mistake.
Are any of these solutions feasible?
move count and points into a new data type so they can be locked together (not implemented; not performant)
Is it possible to document the preconditions for accessing
SeriesBuffersafely across threads? It looks to me that the stored data and the description of the stored data can be updated across threads independently, leaving the risk of them getting out of sync.In more detail, the number of data points in a
SeriesBuffercan be changed independent of the actual points:even across threads. Put another way, a race on individual struct members is not possible, but a race between them is. With just the right (well, wrong) implementation and execution conditions, the count can be left inaccurate.
It appears that the
SeriesBufferGuardis designed to ameliorate this:as it provides a means to update
countwhile the mutex is locked. This seems reasonable to me (and a clever idea!), provided thatcountis only updated through the guard. This condition is met inSeriesBufferGuard::extend():but it is not explicitly met in
SeriesBuffer::take():I think that this implementation works in practice due to the drop scope of guard
points:SeriesBufferGuard::extend()from being called (because anotherSeriesBufferGuard) can not existThis is implicit behavior, and leaves a foot-gun for future developers if the drop scope is changed:
As this precondition isn't enforced by the type system or hinted at in documentation, I could see a future developer not noticing this pitfall and making this or a similar mistake.
Are any of these solutions feasible?
countandpointsinto a new data type so they can be locked together (not implemented; not performant)countthrough theSeriesBufferGuard(see fix: update point count while MutexGuard is held #140)countandpointsinto a new data type that enforces thread-safe read and write (see refactor: add SeriesBufferInner type #144)