I have a requirement to create a network receiver thread by storing the thread join handle inside a network receiver struct. But I'm getting errors error[E0506]: cannot assign to self.join_handle because it is borrowed
and error[E0521]: borrowed data escapes outside of associated function
, while I'm creating the thread inside the start method. This is my code
use std::thread;
use std::sync::atomic::{AtomicBool, Ordering};
pub struct NetworkReceiver {
terminate_flag: AtomicBool,
join_handle: Option<thread::JoinHandle<()>>
}
impl NetworkReceiver {
pub fn new() -> NetworkReceiver {
let net_recv_intf = NetworkReceiver {
terminate_flag: AtomicBool::new(false),
join_handle: None
};
net_recv_intf
}
pub fn start(&mut self) {
self.join_handle = Some(thread::spawn(|| self.run()));
}
pub fn run(&mut self) {
while !self.terminate_flag.load(Ordering::Relaxed) {
}
}
pub fn terminate(&mut self) {
self.terminate_flag.store(true, Ordering::Relaxed);
}
}
CodePudding user response:
You could separate the join_handle
from everything else inside NetworkReceiver
like this:
use std::thread;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
pub struct NetworkReceiver {
terminate_flag: AtomicBool,
}
pub struct RunningNetworkReceiver {
join_handle: thread::JoinHandle<()>,
network_receiver: Arc<NetworkReceiver>,
}
impl NetworkReceiver {
pub fn new() -> NetworkReceiver {
let net_recv_intf = NetworkReceiver {
terminate_flag: AtomicBool::new(false),
};
net_recv_intf
}
pub fn start(self) -> RunningNetworkReceiver {
let network_receiver = Arc::new(self);
let join_handle = {
let network_receiver = network_receiver.clone();
thread::spawn(move || network_receiver.run())
};
RunningNetworkReceiver {
join_handle,
network_receiver,
}
}
pub fn run(&self) {
while !self.terminate_flag.load(Ordering::Relaxed) {
}
}
}
impl RunningNetworkReceiver {
pub fn terminate(&self) {
self.network_receiver.terminate_flag.store(true, Ordering::Relaxed);
}
}
If you need exclusive acces to anything inside of NetworkReceiver
after all you'd have to wrap it (or the part that needs it) in a RwLock
or Mutex
or similar.
CodePudding user response:
When using variables in a thread, that thread must have ownership. This line (thread::spawn(|| self.run());
tries to move self
into the thread but cannot because self
needs to outlive the function.
I beleive you'll have to wrap your NetworkReceiver within an Arc Mutex. You could change your NetworkReceiver::new()
to return a Arc<Mutex> and all the associated functions would change from fn foo(&mut self)
to fn foo(self: Arc<Self>)
CodePudding user response:
use std::thread;
use std::sync::atomic::{AtomicBool, Ordering};
pub struct NetworkReceiver {
terminate_flag: AtomicBool,
join_handle: Option<thread::JoinHandle<()>>
}
impl NetworkReceiver {
pub fn new() -> NetworkReceiver {
let net_recv_intf = NetworkReceiver {
terminate_flag: AtomicBool::new(false),
join_handle: None
};
net_recv_intf
}
pub fn start(&mut self) {
let join_handle = thread::spawn(|| self.run());
self.join_handle = Some(join_handle);
}
fn run(&self) {
let mut buff: [u8; 2048] = [0; 2048];
while !self.terminate_flag.load(Ordering::Relaxed) {
// Do something here
}
}
pub fn terminate(&mut self) {
self.terminate_flag.store(true, Ordering::Relaxed);
}
}
fn main() {
let mut net_recv = NetworkReceiver::new();
net_recv.start();
net_recv.terminate();
}
I've made a few changes to the code you provided:
I've added a main function that creates an instance of NetworkReceiver and calls the start() and terminate() methods on it. I've made the run() method a private method because it should only be called by the start() method. I've made the run() method take a reference to self instead of a mutable reference, because it doesn't modify the NetworkReceiver instance.