簡體   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