Struct glommio::ScopedTask [−][src]
pub struct ScopedTask<'a, T>(_, _);
Expand description
A spawned future that cannot be detached, and has a predictable lifetime.
Because their lifetimes are bounded, you don’t need to make sure that data
you pass to the ScopedTask
is 'static
, which can be cheaper (no need to
reference count). If you, however, would like to .detach
this task and
have it run in the background, consider using Task
instead.
Tasks are also futures themselves and yield the output of the spawned future.
When a task is dropped, its gets canceled and won’t be polled again. To
cancel a task a bit more gracefully and wait until it stops running, use the
cancel()
method.
Tasks that panic get immediately canceled. Awaiting a canceled task also causes a panic.
Safety
ScopedTask
is safe to use so long as it is guaranteed to be either awaited
or dropped. Rust does not guarantee that destructors will be called, and if
they are not, ScopedTask
s can be kept alive after the scope is terminated.
Typically, the only situations in which drop
is not executed are:
- If you manually choose not to, with
std::mem::forget
orManuallyDrop
. - If cyclic reference counts prevents the task from being destroyed.
If you believe any of the above situations are present (the first one is,
of course, considerably easier to spot), avoid using the ScopedTask
.
Examples
use glommio::{LocalExecutor, ScopedTask}; let ex = LocalExecutor::default(); ex.run(async { let a = 2; let task = unsafe { ScopedTask::local(async { println!("Hello from a task!"); 1 + a // this is a reference, and it works just fine }) }; assert_eq!(task.await, 3); });
The usual borrow checker rules apply. A ScopedTask
can acquire a mutable
reference to a variable just fine:
let mut a = 2; let task = unsafe { ScopedTask::local(async { a = 3; }) }; task.await; assert_eq!(a, 3);
But until the task completes, the reference is mutably held so we can no longer immutably reference it:
let mut a = 2; let task = unsafe { ScopedTask::local(async { a = 3; }) }; assert_eq!(a, 3); // task hasn't completed yet! task.await;
You can still use Cell
and RefCell
normally to work around this.
Just keep in mind that there is no guarantee of ordering for execution of
tasks, and if the task has not yet finished the value may or may not have
changed (as with any interior mutability)
let a = Cell::new(2); let task = unsafe { ScopedTask::local(async { a.set(3); }) }; assert!(a.get() == 3 || a.get() == 2); // impossible to know if it will be 2 or 3 task.await; assert_eq!(a.get(), 3); // The task finished now. //
The following code, however, will access invalid memory as drop is never executed
{ let a = &mut "mayhem"; let task = unsafe { ScopedTask::local(async { *a = "doom"; }) }; std::mem::forget(task); }
Implementations
Spawns a task onto the current single-threaded executor.
If called from a LocalExecutor
, the task is spawned on it.
Otherwise, this method panics.
Safety
ScopedTask
depends on drop
running or .await
being called for
safety. See the struct ScopedTask
for details.
Examples
use glommio::{LocalExecutor, ScopedTask}; let local_ex = LocalExecutor::default(); local_ex.run(async { let non_static = 2; let task = unsafe { ScopedTask::local(async { 1 + non_static }) }; assert_eq!(task.await, 3); });
pub unsafe fn local_into(
future: impl Future<Output = T> + 'a,
handle: TaskQueueHandle
) -> Result<Self, ()>
pub unsafe fn local_into(
future: impl Future<Output = T> + 'a,
handle: TaskQueueHandle
) -> Result<Self, ()>
Spawns a task onto the current single-threaded executor, in a particular task queue
If called from a LocalExecutor
, the task is spawned on it.
Otherwise, this method panics.
Safety
ScopedTask
depends on drop
running or .await
being called for
safety. See the struct ScopedTask
for details.
Examples
use glommio::{Local, LocalExecutor, ScopedTask, Shares}; let local_ex = LocalExecutor::default(); local_ex.run(async { let handle = Local::create_task_queue( Shares::default(), glommio::Latency::NotImportant, "test_queue", ); let non_static = 2; let task = unsafe { ScopedTask::<usize>::local_into(async { 1 + non_static }, handle) .expect("failed to spawn task") }; assert_eq!(task.await, 3); })
Cancels the task and waits for it to stop running.
Returns the task’s output if it was completed just before it got
canceled, or None
if it didn’t complete.
While it’s possible to simply drop the ScopedTask
to cancel it, this
is a cleaner way of canceling because it also waits for the task to
stop running.
Examples
use futures_lite::future; use glommio::{LocalExecutor, ScopedTask}; let ex = LocalExecutor::default(); ex.run(async { let task = unsafe { ScopedTask::local(async { loop { println!("Even though I'm in an infinite loop, you can still cancel me!"); future::yield_now().await; } }) }; task.cancel().await; });
Trait Implementations
Auto Trait Implementations
impl<'a, T> RefUnwindSafe for ScopedTask<'a, T> where
T: RefUnwindSafe,
impl<'a, T> !Send for ScopedTask<'a, T>
impl<'a, T> !Sync for ScopedTask<'a, T>
impl<'a, T> Unpin for ScopedTask<'a, T>
impl<'a, T> UnwindSafe for ScopedTask<'a, T> where
T: RefUnwindSafe + UnwindSafe,
Blanket Implementations
Mutably borrows from an owned value. Read more
A convenience for calling Future::poll()
on !
Unpin
types.
Returns the result of self
or other
future, preferring self
if both are ready. Read more
Returns the result of self
or other
future, with no preference if both are ready. Read more
Catches panics while polling the future. Read more
Boxes the future and changes its type to dyn Future + Send + 'a
. Read more
Instruments this type with the provided Span
, returning an
Instrumented
wrapper. Read more
into_future
)The output that the future will produce on completion.
type Future = F
type Future = F
into_future
)Which kind of future are we turning this into?
into_future
)Creates a future from a value.