[mio] 增加统计、监听器、定时器
This commit is contained in:
@@ -0,0 +1,96 @@
|
|||||||
|
use std::sync::atomic::{AtomicU64, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
/// 并发计数器,销毁计数器并不会释放计数槽,这不适用计数器会多次创建销毁的场景
|
||||||
|
pub struct U64Adder {
|
||||||
|
inner: Arc<U64AdderInner>,
|
||||||
|
index: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct U64AdderInner {
|
||||||
|
global: AtomicU64,
|
||||||
|
base: Vec<AtomicU64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl U64AdderInner {
|
||||||
|
pub fn get(&self) -> u64 {
|
||||||
|
let mut count = self.global.load(Ordering::Relaxed);
|
||||||
|
for counter in self.base.iter() {
|
||||||
|
let num = counter.load(Ordering::Relaxed);
|
||||||
|
if num > 1 {
|
||||||
|
count = count + num - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl U64Adder {
|
||||||
|
/// 计数槽容量
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
let mut base = Vec::with_capacity(capacity);
|
||||||
|
base.push(AtomicU64::new(1));
|
||||||
|
for _ in 1..capacity {
|
||||||
|
base.push(AtomicU64::new(0))
|
||||||
|
}
|
||||||
|
let inner = Arc::new(U64AdderInner {
|
||||||
|
global: AtomicU64::new(0),
|
||||||
|
base,
|
||||||
|
});
|
||||||
|
U64Adder {
|
||||||
|
inner,
|
||||||
|
index: Some(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn add(&mut self, num: u64) {
|
||||||
|
if let Some(index) = self.index {
|
||||||
|
let counter = &self.inner.base[index];
|
||||||
|
let i = counter.load(Ordering::Relaxed);
|
||||||
|
counter.store(i + num, Ordering::Relaxed);
|
||||||
|
} else {
|
||||||
|
self.inner.global.fetch_add(num, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get(&self) -> u64 {
|
||||||
|
self.inner.get()
|
||||||
|
}
|
||||||
|
pub fn watch(&self) -> WatchU64Adder {
|
||||||
|
WatchU64Adder {
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for U64Adder {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let mut index: Option<usize> = None;
|
||||||
|
for (i, counter) in self.inner.base.iter().enumerate() {
|
||||||
|
//占用一个空闲的计数槽
|
||||||
|
if counter.load(Ordering::Acquire) == 0 {
|
||||||
|
if counter
|
||||||
|
.compare_exchange(0, 1, Ordering::AcqRel, Ordering::Relaxed)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
index = Some(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct WatchU64Adder {
|
||||||
|
inner: Arc<U64AdderInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WatchU64Adder {
|
||||||
|
pub fn get(&self) -> u64 {
|
||||||
|
self.inner.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
mod adder;
|
||||||
|
pub use adder::*;
|
||||||
+9
-1
@@ -1 +1,9 @@
|
|||||||
pub mod wait;
|
mod notify;
|
||||||
|
mod result_convert;
|
||||||
|
pub use result_convert::io_convert;
|
||||||
|
mod scheduler;
|
||||||
|
pub use notify::StopManager;
|
||||||
|
pub use scheduler::Scheduler;
|
||||||
|
|
||||||
|
mod counter;
|
||||||
|
pub use counter::*;
|
||||||
|
|||||||
@@ -0,0 +1,143 @@
|
|||||||
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::thread::Thread;
|
||||||
|
use std::{io, thread};
|
||||||
|
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct StopManager {
|
||||||
|
inner: Arc<StopManagerInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StopManager {
|
||||||
|
pub fn new<F>(f: F) -> Self
|
||||||
|
where
|
||||||
|
F: FnOnce() + Send + 'static,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
inner: Arc::new(StopManagerInner::new(f)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn add_listener<F>(&self, name: String, f: F) -> io::Result<Worker>
|
||||||
|
where
|
||||||
|
F: FnOnce() + Send + 'static,
|
||||||
|
{
|
||||||
|
self.inner.add_listener(name, f)
|
||||||
|
}
|
||||||
|
pub fn stop(&self) {
|
||||||
|
self.inner.stop("");
|
||||||
|
}
|
||||||
|
pub fn wait(&self) {
|
||||||
|
self.inner.wait();
|
||||||
|
}
|
||||||
|
pub fn is_stop(&self) -> bool {
|
||||||
|
self.inner.state.load(Ordering::Acquire)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StopManagerInner {
|
||||||
|
listeners: Mutex<(bool, Vec<(String, Box<dyn FnOnce() + Send>)>)>,
|
||||||
|
park_threads: Mutex<Vec<Thread>>,
|
||||||
|
worker_num: AtomicUsize,
|
||||||
|
state: AtomicBool,
|
||||||
|
stop_call: Mutex<Option<Box<dyn FnOnce() + Send>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StopManagerInner {
|
||||||
|
fn new<F>(f: F) -> Self
|
||||||
|
where
|
||||||
|
F: FnOnce() + Send + 'static,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
listeners: Mutex::new((false, Vec::with_capacity(32))),
|
||||||
|
park_threads: Mutex::new(Vec::with_capacity(4)),
|
||||||
|
worker_num: AtomicUsize::new(0),
|
||||||
|
state: AtomicBool::new(false),
|
||||||
|
stop_call: Mutex::new(Some(Box::new(f))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn add_listener<F>(self: &Arc<Self>, name: String, f: F) -> io::Result<Worker>
|
||||||
|
where
|
||||||
|
F: FnOnce() + Send + 'static,
|
||||||
|
{
|
||||||
|
if name.is_empty() {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "name cannot be empty"));
|
||||||
|
}
|
||||||
|
let mut guard = self.listeners.lock();
|
||||||
|
if guard.0 {
|
||||||
|
return Err(io::Error::new(io::ErrorKind::Other, "stopped"));
|
||||||
|
}
|
||||||
|
for (n, _) in &guard.1 {
|
||||||
|
if &name == n {
|
||||||
|
return Err(io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("stop add_listener {:?} name already exists", name),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guard.1.push((name.clone(), Box::new(f)));
|
||||||
|
Ok(Worker::new(name, self.clone()))
|
||||||
|
}
|
||||||
|
fn stop(&self, skip_name: &str) {
|
||||||
|
self.state.store(true, Ordering::Release);
|
||||||
|
let mut guard = self.listeners.lock();
|
||||||
|
guard.0 = true;
|
||||||
|
for (name, listener) in guard.1.drain(..) {
|
||||||
|
if &name == skip_name {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
listener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn wait(&self) {
|
||||||
|
{
|
||||||
|
let mut guard = self.park_threads.lock();
|
||||||
|
guard.push(thread::current());
|
||||||
|
drop(guard);
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
if self.worker_num.load(Ordering::Acquire) == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
thread::park()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn stop_call(&self) {
|
||||||
|
if let Some(call) = self.stop_call.lock().take() {
|
||||||
|
call();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Worker {
|
||||||
|
name: String,
|
||||||
|
inner: Arc<StopManagerInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Worker {
|
||||||
|
fn new(name: String, inner: Arc<StopManagerInner>) -> Self {
|
||||||
|
let _ = inner.worker_num.fetch_add(1, Ordering::AcqRel);
|
||||||
|
Self { name, inner }
|
||||||
|
}
|
||||||
|
fn release0(&self) {
|
||||||
|
let inner = &self.inner;
|
||||||
|
let count = inner.worker_num.fetch_sub(1, Ordering::AcqRel);
|
||||||
|
if count == 1 {
|
||||||
|
for x in inner.park_threads.lock().drain(..) {
|
||||||
|
x.unpark();
|
||||||
|
}
|
||||||
|
self.inner.stop_call();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn stop_all(self) {
|
||||||
|
self.inner.stop(&self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Worker {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.release0();
|
||||||
|
log::info!("stop {}", self.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn io_convert<T, R: Display, F: FnOnce(&io::Error) -> R>(
|
||||||
|
rs: io::Result<T>,
|
||||||
|
f: F,
|
||||||
|
) -> io::Result<T> {
|
||||||
|
rs.map_err(|e| io::Error::new(e.kind(), format!("{},internal error:{:?}", f(&e), e)))
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
use crate::util::StopManager;
|
||||||
|
use std::collections::BinaryHeap;
|
||||||
|
use std::{
|
||||||
|
cmp::Ordering,
|
||||||
|
io,
|
||||||
|
sync::mpsc::{sync_channel, Receiver, SyncSender},
|
||||||
|
time::{Duration, Instant},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DelayedTask {
|
||||||
|
f: Box<dyn FnOnce(&Scheduler) + Send>,
|
||||||
|
next: Instant,
|
||||||
|
}
|
||||||
|
impl Eq for DelayedTask {}
|
||||||
|
impl PartialEq for DelayedTask {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.next.eq(&other.next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialOrd for DelayedTask {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
self.next.partial_cmp(&other.next).map(|ord| ord.reverse())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Ord for DelayedTask {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
self.next.cmp(&other.next).reverse()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enum Op {
|
||||||
|
Task(DelayedTask),
|
||||||
|
Stop,
|
||||||
|
}
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Scheduler {
|
||||||
|
sender: SyncSender<Op>,
|
||||||
|
}
|
||||||
|
impl Scheduler {
|
||||||
|
pub fn new(stop_manager: StopManager) -> io::Result<Self> {
|
||||||
|
let (sender, receiver) = sync_channel::<Op>(32);
|
||||||
|
let s = Self { sender };
|
||||||
|
let s_inner = s.clone();
|
||||||
|
let worker = {
|
||||||
|
let scheduler = s.clone();
|
||||||
|
stop_manager.add_listener("Scheduler".into(), move || {
|
||||||
|
scheduler.shutdown();
|
||||||
|
})?
|
||||||
|
};
|
||||||
|
std::thread::Builder::new()
|
||||||
|
.name("Scheduler".into())
|
||||||
|
.spawn(move || {
|
||||||
|
run(receiver, s_inner);
|
||||||
|
worker.stop_all();
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
Ok(s)
|
||||||
|
}
|
||||||
|
pub fn timeout<F>(&self, time: Duration, f: F) -> bool
|
||||||
|
where
|
||||||
|
F: FnOnce(&Scheduler) + Send + 'static,
|
||||||
|
{
|
||||||
|
let task = DelayedTask {
|
||||||
|
f: Box::new(f),
|
||||||
|
next: Instant::now().checked_add(time).unwrap(),
|
||||||
|
};
|
||||||
|
self.sender.send(Op::Task(task)).is_ok()
|
||||||
|
}
|
||||||
|
pub fn shutdown(self) {
|
||||||
|
let _ = self.sender.send(Op::Stop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
|
||||||
|
let mut binary_heap = BinaryHeap::<DelayedTask>::with_capacity(32);
|
||||||
|
loop {
|
||||||
|
while let Some(task) = binary_heap.peek() {
|
||||||
|
let now = Instant::now();
|
||||||
|
if now < task.next {
|
||||||
|
//需要等待对应时间
|
||||||
|
match receiver.recv_timeout(task.next - now) {
|
||||||
|
Ok(op) => {
|
||||||
|
if add_task(op, &mut binary_heap) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => match e {
|
||||||
|
std::sync::mpsc::RecvTimeoutError::Timeout => continue,
|
||||||
|
std::sync::mpsc::RecvTimeoutError::Disconnected => return,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(task) = binary_heap.pop() {
|
||||||
|
(task.f)(&s_inner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//取出所有任务
|
||||||
|
loop {
|
||||||
|
match receiver.try_recv() {
|
||||||
|
Ok(op) => {
|
||||||
|
if add_task(op, &mut binary_heap) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => match e {
|
||||||
|
std::sync::mpsc::TryRecvError::Empty => break,
|
||||||
|
std::sync::mpsc::TryRecvError::Disconnected => return,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if binary_heap.is_empty() {
|
||||||
|
//任务队列为空时陷入等待
|
||||||
|
if let Ok(op) = receiver.recv() {
|
||||||
|
if add_task(op, &mut binary_heap) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn add_task(op: Op, binary_heap: &mut BinaryHeap<DelayedTask>) -> bool {
|
||||||
|
return match op {
|
||||||
|
Op::Task(task) => {
|
||||||
|
binary_heap.push(task);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
Op::Stop => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user