Mio Registration Semantic Differences


#1

Hello, folks.

I am a couple weeks into my experience with Rust, attempting to establish a system-related communication channel with some number of subordinate threads using mio. Namely, I want to enable graceful shutdown as I am operating in a producer / consumer context and want to provide at least once delivery semantics.

I have found that my expectations of mio breakdown when I attempt to generate mio Registration / SetReadiness in a loop which spawns my subordinate threads.

The following works as expected with 1 worker:

extern crate mio;

use std::collections::HashMap;

fn main(){
    let mut threads : HashMap<String, (std::thread::JoinHandle<bool>, mio::SetReadiness)> = HashMap::new();

  //  for i in 1..2 {
        let poll = mio::Poll::new().unwrap();
        let (registration, set_readiness) = mio::Registration::new2();
    
        poll.register(&registration,
        mio::Token(0),
        mio::Ready::readable(),
        mio::PollOpt::edge()).unwrap();
    
         let thread = std::thread::spawn(move || {
            loop {
                let mut events = mio::Events::with_capacity(1024);
                poll.poll(&mut events, None).unwrap();
                for event in &events {
                    println!("Got event {:?}!", event);
                    if event.readiness().is_readable() {
                        return false;
                    }
                }
                std::thread::sleep(std::time::Duration::from_millis(10));
            }
        });
        
        threads.insert("foo".to_string(), (thread, set_readiness.clone()));
   // }
    
    std::thread::sleep(std::time::Duration::from_millis(1000));
    
    for (id, (handle, set_readiness)) in threads {
        println!("Shutting down {:?}", id);
        set_readiness.set_readiness(mio::Ready::readable()).unwrap();
        handle.join().unwrap();
        set_readiness.set_readiness(mio::Ready::empty()).unwrap();
    }
}

Namely, the child thread notes the readiness and shutsdown when set.

The following example blocks forever, the only difference being that the mio constructs and child thread are constructed within the context of a loop:

extern crate mio;

use std::collections::HashMap;

fn main(){
    let mut threads : HashMap<String, (std::thread::JoinHandle<bool>, mio::SetReadiness)> = HashMap::new();

    for i in 1..2 {
        let poll = mio::Poll::new().unwrap();
        let (registration, set_readiness) = mio::Registration::new2();
    
        poll.register(&registration,
        mio::Token(0),
        mio::Ready::readable(),
        mio::PollOpt::edge()).unwrap();
    
         let thread = std::thread::spawn(move || {
            loop {
                let mut events = mio::Events::with_capacity(1024);
                poll.poll(&mut events, None).unwrap();
                for event in &events {
                    println!("Got event {:?}!", event);
                    if event.readiness().is_readable() {
                        return false;
                    }
                }
                std::thread::sleep(std::time::Duration::from_millis(10));
            }
        });
        
        threads.insert("foo".to_string(), (thread, set_readiness.clone()));
   }
    
    std::thread::sleep(std::time::Duration::from_millis(1000));
    
    for (id, (handle, set_readiness)) in threads {
        println!("Shutting down {:?}", id);
        set_readiness.set_readiness(mio::Ready::readable()).unwrap();
        handle.join().unwrap();
        set_readiness.set_readiness(mio::Ready::empty()).unwrap();
    }
} 

Can someone enlighten me as to what is going on here?


#2

For future reference - I also reached out to the mio community specifically issues/756.