Restore task::spawn_blocking

mio-0-7
k-nasa 5 years ago
parent 84e5c5f351
commit 98cbf7f8eb

@ -1,4 +1,12 @@
use crate::task::{spawn, JoinHandle};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;
use crossbeam_channel::{unbounded, Receiver, Sender};
use once_cell::sync::Lazy;
use crate::task::{JoinHandle, Task};
use crate::utils::abort_on_panic;
/// Spawns a blocking task.
///
@ -35,5 +43,80 @@ where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
spawn(async { f() })
let schedule = |task| POOL.sender.send(task).unwrap();
let (task, handle) = async_task::spawn(async { f() }, schedule, Task::new(None));
task.schedule();
JoinHandle::new(handle)
}
type Runnable = async_task::Task<Task>;
struct Pool {
sender: Sender<Runnable>,
receiver: Receiver<Runnable>,
}
/// The number of sleeping worker threads.
static SLEEPING: AtomicUsize = AtomicUsize::new(0);
static POOL: Lazy<Pool> = Lazy::new(|| {
// Start a single worker thread waiting for the first task.
start_thread();
let (sender, receiver) = unbounded();
Pool { sender, receiver }
});
fn start_thread() {
SLEEPING.fetch_add(1, Ordering::SeqCst);
let timeout = Duration::from_secs(1);
thread::Builder::new()
.name("async-std/blocking".to_string())
.spawn(move || {
loop {
let mut task = match POOL.receiver.recv_timeout(timeout) {
Ok(task) => task,
Err(_) => {
// Check whether this is the last sleeping thread.
if SLEEPING.fetch_sub(1, Ordering::SeqCst) == 1 {
// If so, then restart the thread to make sure there is always at least
// one sleeping thread.
if SLEEPING.compare_and_swap(0, 1, Ordering::SeqCst) == 0 {
continue;
}
}
// Stop the thread.
return;
}
};
// If there are no sleeping threads, then start one to make sure there is always at
// least one sleeping thread.
if SLEEPING.fetch_sub(1, Ordering::SeqCst) == 1 {
start_thread();
}
loop {
// Run the task.
abort_on_panic(|| task.run());
// Try taking another task if there are any available.
task = match POOL.receiver.try_recv() {
Ok(task) => task,
Err(_) => break,
};
}
// If there is at least one sleeping thread, stop this thread instead of putting it
// to sleep.
if SLEEPING.load(Ordering::SeqCst) > 0 {
return;
}
SLEEPING.fetch_add(1, Ordering::SeqCst);
}
})
.expect("cannot start a blocking thread");
}

Loading…
Cancel
Save