为什么 Mio 的民意调查针对用户生成的事件触发了两次?
Why is Mio's poll triggered twice for user-generated events?
以下代码生成一个 "user event" 由 poll
返回:
extern crate mio;
use mio::event::Evented;
use mio::{Events, Poll, PollOpt, Ready, Registration, Token};
use std::thread::{sleep, spawn, JoinHandle};
use std::time::{Duration, Instant};
#[derive(Debug)]
struct Output(u32, Duration);
pub struct MioThread {
registration: Registration,
handle: JoinHandle<Output>,
}
impl MioThread {
pub fn new(i: u32) -> MioThread {
let now = Instant::now();
let (registration, set_readiness) = Registration::new2();
let handle = spawn(move || {
sleep(Duration::from_millis((1000 - (100 * i)) as u64));
set_readiness.set_readiness(Ready::readable()).unwrap();
Output(i, now.elapsed())
});
MioThread {
registration: registration,
handle: handle,
}
}
// manage the thread result
fn eval_result(self) {
let out = self.handle.join();
println!("do whathever you want with: {:?}", out.unwrap());
}
}
fn main() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(16);
let mut tasks = Vec::new();
for i in 0..5 {
let mio_thread = MioThread::new(i);
mio_thread
.registration
.register(&poll, Token(i as usize), Ready::readable(), PollOpt::edge())
.unwrap();
tasks.push(Some(mio_thread));
}
loop {
let num_events = poll.poll(&mut events, None).unwrap();
println!("poll fired: {} events", num_events);
for event in &events {
if event.readiness().is_readable() {
let Token(thread_id) = event.token();
if let Some(t) = tasks.remove(thread_id) {
t.eval_result();
}
}
}
}
}
输出为:
poll fired: 1 events
do whathever you want with: Output(4, Duration { secs: 0, nanos: 600967623 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(3, Duration { secs: 0, nanos: 701035026 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(2, Duration { secs: 0, nanos: 801089370 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(1, Duration { secs: 0, nanos: 900890190 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(0, Duration { secs: 1, nanos: 600076 })
poll fired: 0 events
如评论中所述并确认here:
dropping a Registration might wake up the loop (which it indeed does, the same as a registration) without actually triggering an event
这在大多数情况下显然不是问题,只是我在阅读 docs:
后没想到的行为
fn poll(&self, events: &mut Events, timeout: Option) -> Result[−]
Wait for readiness events
Blocks the current thread and waits for readiness events for any of the Evented handles that have been registered with this Poll instance. The function will block until either at least one readiness event has been received or timeout has elapsed. A timeout of None means that poll will block until a readiness event has been received.
当前线程确实在删除 Registration
.
时也被唤醒
以下代码生成一个 "user event" 由 poll
返回:
extern crate mio;
use mio::event::Evented;
use mio::{Events, Poll, PollOpt, Ready, Registration, Token};
use std::thread::{sleep, spawn, JoinHandle};
use std::time::{Duration, Instant};
#[derive(Debug)]
struct Output(u32, Duration);
pub struct MioThread {
registration: Registration,
handle: JoinHandle<Output>,
}
impl MioThread {
pub fn new(i: u32) -> MioThread {
let now = Instant::now();
let (registration, set_readiness) = Registration::new2();
let handle = spawn(move || {
sleep(Duration::from_millis((1000 - (100 * i)) as u64));
set_readiness.set_readiness(Ready::readable()).unwrap();
Output(i, now.elapsed())
});
MioThread {
registration: registration,
handle: handle,
}
}
// manage the thread result
fn eval_result(self) {
let out = self.handle.join();
println!("do whathever you want with: {:?}", out.unwrap());
}
}
fn main() {
let poll = Poll::new().unwrap();
let mut events = Events::with_capacity(16);
let mut tasks = Vec::new();
for i in 0..5 {
let mio_thread = MioThread::new(i);
mio_thread
.registration
.register(&poll, Token(i as usize), Ready::readable(), PollOpt::edge())
.unwrap();
tasks.push(Some(mio_thread));
}
loop {
let num_events = poll.poll(&mut events, None).unwrap();
println!("poll fired: {} events", num_events);
for event in &events {
if event.readiness().is_readable() {
let Token(thread_id) = event.token();
if let Some(t) = tasks.remove(thread_id) {
t.eval_result();
}
}
}
}
}
输出为:
poll fired: 1 events
do whathever you want with: Output(4, Duration { secs: 0, nanos: 600967623 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(3, Duration { secs: 0, nanos: 701035026 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(2, Duration { secs: 0, nanos: 801089370 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(1, Duration { secs: 0, nanos: 900890190 })
poll fired: 0 events
poll fired: 1 events
do whathever you want with: Output(0, Duration { secs: 1, nanos: 600076 })
poll fired: 0 events
如评论中所述并确认here:
dropping a Registration might wake up the loop (which it indeed does, the same as a registration) without actually triggering an event
这在大多数情况下显然不是问题,只是我在阅读 docs:
后没想到的行为fn poll(&self, events: &mut Events, timeout: Option) -> Result[−] Wait for readiness events
Blocks the current thread and waits for readiness events for any of the Evented handles that have been registered with this Poll instance. The function will block until either at least one readiness event has been received or timeout has elapsed. A timeout of None means that poll will block until a readiness event has been received.
当前线程确实在删除 Registration
.