在线程中使用特征方法

时间:2015-02-15 06:57:45

标签: multithreading design-patterns rust

基本上,我正在制作一个程序,它正在监听一堆端口,并以不同的方式处理传入的数据包。我决定将此代码捆绑到特征:

use std::old_io::{TcpStream, TcpListener, Listener, Acceptor, EndOfFile, IoResult};
use std::thread::Thread;

trait Server {
    fn new(port: u16) -> Self;

    fn hostname(&self) -> &String;

    fn initialize(&self) {
        let acceptor = TcpListener::bind(self.hostname().as_slice()).listen().unwrap();
        Thread::spawn(move|| {
            let mut acceptor = acceptor;
            for incoming_stream in acceptor.incoming() {
                match incoming_stream {
                    Ok(stream) => {
                        self.handle_client(stream);
                    },
                    Err(ref e) if e.kind == EndOfFile => break,
                    Err(e) => panic!("Unexpected error: {}", e),
                }
            }
        });
    }

    fn handle_client(&self, stream: TcpStream) -> ();
}

pub struct InternodeServer {
    hostname: String,
}

impl Server for InternodeServer {
    fn new(port: u16) -> InternodeServer {
        let hostname = format!("127.0.0.1:{}", port);
        InternodeServer {
            hostname: hostname,
        }
    }

    fn hostname(&self) -> &String {
        &self.hostname
    }

    fn handle_client(&self, stream: TcpStream) {
        println!("Received connection");
        let mut stream = stream;
        let response = b"Hello\r\n";
        let _ = stream.write_all(response);
        let _ = stream.close_write();
    }
}

fn main() {
    let test_server = <InternodeServer as Server>::new(9337);
    test_server.initialize();
}

但是,此代码无效,因为您无法发送Self。这是我收到的错误:

test.rs:11:9: 11:22 error: the trait `core::marker::Send` is not implemented for the type `Self` [E0277]
test.rs:11         Thread::spawn(move|| {
                   ^~~~~~~~~~~~~
test.rs:11:9: 11:22 note: `Self` cannot be sent between threads safely
test.rs:11         Thread::spawn(move|| {
                   ^~~~~~~~~~~~~

所以我也尝试使handle_client成为静态方法以避免自我。为此,我只需将handle_client更改为:

fn handle_client(stream: TcpStream)

并通过以下方式引用它:

Server::handle_client(stream);

但是,我无法从Server的initialize方法引用InternodeServer的静态方法。编译时,我收到如下错误:

test.rs:16:25: 16:46 error: type annotations required: cannot resolve `_ : Server` [E0283]
test.rs:16                         Server::handle_client(stream);
                                   ^~~~~~~~~~~~~~~~~~~~~
test.rs:16:25: 16:46 note: required by `Server::handle_client`
test.rs:16                         Server::handle_client(stream);

有什么方法吗?

2 个答案:

答案 0 :(得分:1)

我不认为rust会让你直接从其他线程调用对象方法,因为“move”闭包不能借用任何东西,只能移动。

所以你必须使用某种线程间通信工具,例如,频道:

use std::thread::Thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use std::net::{TcpStream, TcpListener};
use std::io::{ErrorKind, Write};

trait Server {
    fn new(port: u16) -> Self;

    fn hostname(&self) -> &String;

    fn initialize(&mut self, _detached: bool) {
        let acceptor = TcpListener::bind(self.hostname().as_slice()).unwrap();
        let server_tx = self.make_pipe();
        Thread::spawn(move|| {
            for incoming_stream in acceptor.incoming() {
                match incoming_stream {
                    Ok(stream) => server_tx.send(Arc::new(Mutex::new(stream))).unwrap(),
                    Err(ref e) if e.kind() == ErrorKind::NotConnected => break,
                    Err(e) => panic!("Unexpected error: {}", e),
                }
            }
        });
    }

    fn handle_client(&self, stream: Arc<Mutex<TcpStream>>);
    fn make_pipe(&mut self) -> Sender<Arc<Mutex<TcpStream>>>;
    fn run(&self);
}

pub struct InternodeServer {
    hostname: String,
    client_rx: Option<Receiver<Arc<Mutex<TcpStream>>>>,
}

impl Server for InternodeServer {
    fn new(port: u16) -> InternodeServer {
        let hostname = format!("127.0.0.1:{}", port);
        InternodeServer {
            hostname: hostname,
            client_rx: None,
        }
    }

    fn make_pipe(&mut self) -> Sender<Arc<Mutex<TcpStream>>> {
        let (server_tx, client_rx) = channel();
        self.client_rx = Some(client_rx);
        server_tx
    }

    fn hostname(&self) -> &String {
        &self.hostname
    }

    fn handle_client(&self, stream_arc: Arc<Mutex<TcpStream>>) {
        println!("Received connection");
        let mut stream = stream_arc.lock().unwrap();
        let response = b"Hello\r\n";
        let _ = stream.write_all(response);
        let _ = drop(stream);
    }

    fn run(&self) {
        loop {
            match self.client_rx.as_ref().unwrap().recv() {
                Ok(stream) => self.handle_client(stream),
                Err(RecvError) => break,
            }
        }
    }
}

fn main() {
    let mut s = <InternodeServer as Server>::new(10101);
    s.initialize(false);
    s.run();
}

答案 1 :(得分:1)

这是一个较小的错误再现:

use std::thread::Thread;

trait Server {
    fn initialize(&self) {
        Thread::spawn(move || self.handle_client());
    }

    fn handle_client(&self);
}

fn main() {}

问题是传递给Thread::spawn的参数必须是Send。您正试图将self移到闭包中,但您的特性不能保证Send,因此闭包不能是Send

我们可以尝试使用trait Server: Send沿着该路径前进,但接着我们得到“无法推断出适当的生命周期”错误,因为Send还需要'staticfor now) 。此外,将自己移动到闭包中似乎很奇怪。

真的,我想你想分开你的代码。将handle_client移到单独的特征中,然后确保该特征的实现为Send

use std::thread::Thread;

trait Server {
    fn initialize<D>(&self, driver: D)
        where D: Driver + Send
    {
        Thread::spawn(move || driver.handle_client());
    }
}

trait Driver {
    fn handle_client(&self);
}

fn main() {}