Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Concurrency primitives in sync.rs with static enforcement. #3145

Closed
bblum opened this issue Aug 8, 2012 · 3 comments
Closed

Concurrency primitives in sync.rs with static enforcement. #3145

bblum opened this issue Aug 8, 2012 · 3 comments
Labels
A-lifetimes Area: lifetime related E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot.

Comments

@bblum
Copy link
Contributor

bblum commented Aug 8, 2012

These will serve as enhanced versions of arc::exclusive. The plan is for mutex_arc to be the same as exclusive, but scheduler enabled, and come equipped with a working condition variable. It is marked unsafe because you can still create cycles with it (benefit: you can nest them).

rw_arc is somewhat more advanced, and notably more safe. The const serves two purposes - it allows handing out immutable references while in read mode (just like arc::arc does today), and it also prevents nesting them inside each other, since they won't be const themselves.

I am also thinking of exposing semaphores, with acquire and release and potentially also cond_wait and cond_signal. These wouldn't protect anything themselves, but could perhaps be used to synchronise beyond-rust shared resources, such as the filesystem.

Proposed interface:

trait condvar {
    fn signal();
    fn wait();
}

impl <T: send> for &mutex_arc<T> {
    unsafe fn access<U>(blk: fn(&mut T) -> U) -> U;
    unsafe fn access_cond<U>(blk: fn(&mut T, condvar) -> U) -> U;
}

impl <T: const send> for &rw_arc<T> {
    // Read mode
    fn access_read<U>(blk: fn(&T) -> U) -> U;

    // Write mode
    fn access<U>(blk: fn(&mut T) -> U) -> U;
    fn access_cond<U>(blk: fn(&mut T, &condvar) -> U) -> U;
    fn access_downgrade<U>(blk: fn(+write_mode<T>) -> U) -> U;
}

fn downgrade<T: const send>(+write_mode<T>) -> read_mode<T>;

impl <T: const send> for &write_mode<T> {
    fn access<U>(blk: fn(&mut T) -> U) -> U;
    fn access_cond<U>(blk: fn(&mut T, &condvar) -> U) -> U;
}

impl <T: const send> for &read_mode<T> {
    fn access<U>(blk: fn(&T) -> U) -> U;
}

A couple points:

  • The condvar is just like rust_cond_lock very-unsafely provided in the past.

cvar example:

do mutex_arc.access_cond |state, cond| {
    ...
    while not_satisfied(state) {
        cond.wait();
    }
    ...
}
  • I don't think it's meaningful to hand out a condition variable for rws in read-mode. And it'd be a bunch nastier to implement. Feel free to argue, but I think that (a) signalling on one is meaningless, since you can't have changed anything inside, and (b) waiting on one is meaningless, because either you forbid writers from going before you wake (in which case what are you waiting for?) or writers can go (in which case you might as well have dropped the lock wholesale).
  • Downgrade is really neat (hopefully). The read_mode and write_mode are linear tokens that allow you to access the state, and downgrade consumes the write mode. This allows you atomically downgrade without releasing the lock, while statically enforcing no mutation after the downgrade.

Downgrade example:

do rw_arc.access_downgrade |write_mode| {
    do write_mode.access |state| {
        ... mutate state ...
    }
    let read_mode = downgrade(write_mode);
    do read_mode.access |state| {
        ... state is immutable ...
    }
}

In particular, I would like confirmation that my understanding of region pointers will enforce the im/mutability properties.

@ghost ghost assigned bblum Aug 8, 2012
@nikomatsakis
Copy link
Contributor

Regarding the immutability properties, I believe this scheme will work.

@bblum
Copy link
Contributor Author

bblum commented Aug 9, 2012

It looks like both the condvar and the downgrade token can have a region pointer inside and thus be prevented from escaping. 904a74e (sync-cond-shouldnt-escape.rs) demonstrates this.

@bblum
Copy link
Contributor Author

bblum commented Aug 15, 2012

This is done. std::arc is where the shared state stuff lives; std::sync is where the bare mutexes/rwlocks/semaphores live.

It should go without saying that pipes are still the preferred communication mechanism when they will suffice - after all, these are implemented on top of pipes.

@bblum bblum closed this as completed Aug 15, 2012
@bblum bblum removed their assignment Jun 16, 2014
bors pushed a commit to rust-lang-ci/rust that referenced this issue May 15, 2021
RalfJung pushed a commit to RalfJung/rust that referenced this issue Nov 4, 2023
give some more help for the unusual data races

Fixes rust-lang/miri#3142
celinval pushed a commit to celinval/rust-dev that referenced this issue Jun 4, 2024
Prior to this commit, errors thrown when evaluating the text of a
benchcomp extra column would crash benchcomp. This could happen, for
example, if a column tries to compare an old variant with a new one, but
no data for the old variant exists, as seen in this run:

https://github.com/model-checking/kani/actions/runs/8700040930/job/23859607740

Forcing the user to do error handling in the column text would make the
text even more unwieldy than it already is, so this commit makes the
column text evaluate to **<ERROR>** if an exception is raised during
evaluation.

By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 and MIT licenses.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: lifetime related E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot.
Projects
None yet
Development

No branches or pull requests

2 participants