Casting lvalues
tsbockman
thomas.bockman at gmail.com
Fri Apr 2 20:23:42 UTC 2021
On Friday, 2 April 2021 at 12:47:35 UTC, z wrote:
> Even if the function is changed to only accept `shared`
> parameters, `.reserve` does not appear to support `shared` so
> the function is impossible to use without somehow changing its
> type or using `__gshared`.
There is no way that `.reserve` can correctly support `shared`,
because it cannot know how to correctly synchronize the slice and
its contents in the larger context of the whole program.
In general, just casting away `shared` to make the compiler stop
complaining completely defeats the purpose of `shared`, and makes
it just as unsafe as `__gshared`.
Instead, you must do any necessary synchronization yourself
using, for example, `core.sync.mutex`. Only within properly
synchronized regions should you cast away `shared`. This is the
purpose of `shared`, and the only difference from `__gshared`: to
remind you to synchronize by requiring the use of a cast to do
much of anything.
Typically, you should synchronize an entire region of code across
which the `shared` data under protection will begin and end with
all invariants satisfied. Synchronizing individual operations
(like just `.reserve` by itself) is usually wrong - or rather,
insufficient.
The synchronization must guarantee that whenever a thread is
writing to the data, it has exclusive access. But, it is safe and
fast to have multiple threads read data simultaneously, as long
as it is not written to during that time. `core.sync.rwmutex` can
be used to implement this optimization.
(It is possible to design algorithms that support multiple
simultaneous writers using lock-free algorithms (see
`core.atomic`) or other more complicated schemes, but this is
much harder to do correctly and usually not necessary.)
Finally, if you only need to write the data once, after which it
will only be read, then you can skip all of this confusion and
complexity by just preparing the data from a single thread in a
non-`shared` container and then using `cast(immutable)` (if there
is only one extant reference to the data) or `.idup` (otherwise).
No synchronization is necessary for `immutable` data.
> `*(cast(Unqual!TT*)&a)`, not ideal
That is the correct way to perform an lvalue reinterpret cast
(provided that the resulting type is actually compatible with the
source type).
> (direct casting seems to create an rvalue because compilation
> fails.)
Yes, direct casting should result in an rvalue. (Although, I
think it is possible to subvert this with a custom `opCast`.)
More information about the Digitalmars-d-learn
mailing list