繁体   English   中英

在线程中使用特征方法

[英]Using trait methods in threads

基本上,我正在编写一个侦听一堆端口并以不同方式处理传入数据包的程序。 我决定将此代码捆绑为一个Trait:

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设为静态方法以避免self。 为此,我只是将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);

有没有办法解决?

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

因此,您必须使用某种线程间通信工具,例如通道:

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();
}

这是该错误的较小再现:

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还需要'static目前 )。 同样, 将自己置于封闭状态似乎很奇怪。

确实,我认为您想拆分代码。 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() {}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM