Conversation
|
Can we avoid having to specify the (Edit: Nevermind, I missed the "Future Work" section.) |
|
Should be ready for review now. Note that this PR is blocked by #6603 . |
| fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { | ||
| // If the resource can't be shared between threads, make sure it runs on the main thread. | ||
| // FIXME: We should be able to register access as 'exclusive reads' to prevent shared access | ||
| // without forcing the system to run on the main thread. |
There was a problem hiding this comment.
IMO, there's no point to merging this PR as is without this. You would otherwise just use a NonSend for the same effect.
You can treat a Res<T: !Sync> the same as ResMut<T: !Sync>. Move the if !T::IS_SYNC down below, and change the non-Sync branch to add a write instead.
There was a problem hiding this comment.
IMO, there's no point to merging this PR as is without this. You would otherwise just use a NonSend for the same effect.
I want to keep this PR as small as possible, so it's easier to review. If this gets merged, I'll open a follow-up PR that makes the Access changes.
These changes are easily separable, so I see no reason to roll them up into one PR. Especially since the Access changes are just an optimization.
Also, this already allows ResMut<T: !Sync> to be used off of the main thread.
You can treat a Res<T: !Sync> the same as ResMut<T: !Sync>. Move the if !T::IS_SYNC down below, and change the non-Sync branch to add a write instead.
This won't work, it will mess up ambiguity detection.
| impl #impl_generics #bevy_ecs_path::system::Resource for #struct_name #type_generics #where_clause { | ||
| // SAFETY: The trait bounds on this impl guarantee that the non-`Sync` types will not have `IS_SYNC = true`. | ||
| unsafe impl #impl_generics #bevy_ecs_path::system::Resource for #struct_name #type_generics #where_clause { | ||
| const IS_SYNC: bool = #is_sync; |
There was a problem hiding this comment.
These should definitely have some compile fail tests to ensure that this breaks when this contract is broken.
Separately, we should see if the compile failures are readable by normal users.
There was a problem hiding this comment.
I added a compile fail test. The error message isn't great, but it isn't any worse than before this PR.
I tried a few ways of providing a more descriptive error message, but they all caused problems in edge cases.
There was a problem hiding this comment.
After investigating further, the error message is actually good for concrete types. It shows up when you define the struct, and points you directly to the field that makes the struct !Sync.
It's less good for generic types, because the error doesn't occur until you try to use the resource.
// Concrete types:
#[derive(Resource)] // error message shows up here, right where we want it.
struct MyResource(Cell<u32>);// Generic types:
#[derive(Resource)]
struct MyResource<T>(Cell<T>);
// The error message doesn't show up until here, which is un-ideal.
fn my_system(_: Res<MyResource<u32>>) {}IMO this isn't perfect, but it's perfectly acceptable.
This reverts commit 47a144a.
4afed44 to
c3b681c
Compare
|
This is no longer blocked by #6603. |
|
I'm closing this in favor of #6864 -- this all seems a bit unnecessary when you could just wrap your |
|
For what it's worth, I do think |
|
could we create our own wrapper that would only trigger change detection on mutable access to the inner value? |
|
.We'd need to be aware that the type is |
# Objective It's not clear to users how to handle `!Sync` types as components and resources in the absence of engine level support for them. ## Solution Added a section to `Component`'s and `Resource`'s type level docs on available options for making a type `Sync` when it holds `!Sync` fields, linking `bevy_utils::synccell::SyncCell` and the currently unstable `std::sync::Exclusive`. Also added a compile_fail doctest that illustrates how to apply `SyncCell`. These will break when/if #6572 gets merged, at which point these docs should be updated.
…ine#6864) # Objective It's not clear to users how to handle `!Sync` types as components and resources in the absence of engine level support for them. ## Solution Added a section to `Component`'s and `Resource`'s type level docs on available options for making a type `Sync` when it holds `!Sync` fields, linking `bevy_utils::synccell::SyncCell` and the currently unstable `std::sync::Exclusive`. Also added a compile_fail doctest that illustrates how to apply `SyncCell`. These will break when/if bevyengine#6572 gets merged, at which point these docs should be updated.
…ine#6864) # Objective It's not clear to users how to handle `!Sync` types as components and resources in the absence of engine level support for them. ## Solution Added a section to `Component`'s and `Resource`'s type level docs on available options for making a type `Sync` when it holds `!Sync` fields, linking `bevy_utils::synccell::SyncCell` and the currently unstable `std::sync::Exclusive`. Also added a compile_fail doctest that illustrates how to apply `SyncCell`. These will break when/if bevyengine#6572 gets merged, at which point these docs should be updated.
Objective
Allow non-
Synctypes to be used as resources, without having to resort toNonSend<>.Currently, non-
Synctypes are conflated with non-Sendtypes, which results in overly restrictive scheduling. Any system that uses non-Sendtypes must be run on the main thread, which increases thread contention and prevents parallelization. This is unnecessary, asSend + !Syncresources could be accessed from any thread, as long as it's only one at a time.Solution
Resource: Sync.Resourcetrait tracks whether each type isSync. The scheduler ensures that shared access to non-Synctypes does not occur.Example
Future Work
For the time being, systems with read-only access to a non-
Syncresource are run on the main thread. This is overly restrictive: we will need to update ourAccessmodel to properly support non-Syncreads.Changelog
Resourcenow supports types that do not implementstd::marker::Sync.Migration Guide
The
Resourcetrait is nowunsafeto implement manually. Use of the derive macro is recommended.Any generic code that relied on
Resource: Syncwill now need to specify theSyncbound.