Reputation: 428
I'm trying to write a simple library that has a background worker thread that processes commands when the library functions are called.
The way that I would normally do it in C is have a global semaphore handle that the worker would block on. The functions would give the semaphore after they sent a command, at which point the worker would unblock etc... There are other ways but this is just an example.
I have a few questions about how I can achieve something similar with Rust.
How do I prevent a thread from closing once the function that created it returns? e.g the thread would be created when I call init()
, but would exit when init()
returns, how to prevent this?
How to have a have a global synchronization method between the worker thread and function calls? I was looking at using channels but how do I access the rx
from the thread and multiple tx
's from different functions? e.g send_cmd_a()
, send_cmd_b()
to the same thread
Pseudo code of what I'm trying to accomplish:
static (tx, rx) = mpsc::channel(); //how to do something like this?
fn init() {
thread::spawn(|| {
loop {
let cmd = rx.recv().unwrap(); //blocks till there is data
//process data....
if cmd == "exit" {
return;
}
}
});
}
fn send_cmd_a() {
//Do a bunch of other stuff...
tx.send("cmd_a").unwrap();
}
fn exit() {
tx.send("exit").unwrap();
}
Do I have to create one big object that encapsulates all of this, thus owning the synchronization mechanism? (still doesn't answer question #1)
What would be the preferred way of doing something like this in Rust?
Upvotes: 4
Views: 3370
Reputation: 428
I think I figured out a way to implement what I wanted in Rust without needing to use global variables.
struct Device {
sender: Sender<u8>, //other stuff
}
trait New {
fn new() -> Self;
}
trait SendCommand {
fn send_command(&self, u8);
}
impl New for Device {
fn new() -> Device {
let (tx, rx) = channel();
let device = Device { sender: tx };
thread::spawn(move || {
loop {
let cmd = rx.recv().unwrap();
println!("Command: {}", cmd); //process commands here
}
});
return device;
}
}
impl SendCommand for Device {
fn send_command(&self, cmd: u8) {
self.sender.send(cmd).unwrap();
}
}
fn main() {
let dev = Device::new(); //create the device
for i in 0..10 {
dev.send_command(i); //send commands
sleep(Duration::from_millis(50));
}
loop {}
}
Upvotes: 3