How to close a rusqlite connection in a mutex? - rust

I have a rusqlite connect in a mutex
as follows:
struct MyStruct {
connection: std::sync::Mutex<rusqlite::Connection>,
}
When I'm finished with it I want to close it, which I attempted to do as follows:
let lock_ro = mystruct.connection.lock().unwrap();
lock_ro.close()
.map_err(|e| e.1)
.with_context(|| format!("failed to close))?;
However I get this error:
error[E0507]: cannot move out of dereference
of std::sync::MutexGuard<'_, rusqlite::Connection>
and: ^^^^^^^ move occurs because value has type
rusqlite::Connection, which does not implement the Copy trait
If I can't move it how can I close it?

If MyStruct is shared between threads when you want to close it, you can store it as an Option:
struct MyStruct {
connection: std::sync::Mutex<Option<rusqlite::Connection>>,
}
So then when you want to close it, you can take ownership of the value via .take() and then call .close():
mystruct.connection
.lock()
.expect("lock should not be poisoned")
.take()
.expect("there should be a connection")
.close()
.map_err(|e| e.1)
.with_context(|| format!("failed to close"))?;

Related

How do I define the lifetime for a tokio task spawned from a class?

I'm attempting to write a generic set_interval function helper:
pub fn set_interval<F, Fut>(mut f: F, dur: Duration)
where
F: Send + 'static + FnMut() -> Fut,
Fut: Future<Output = ()> + Send + 'static,
{
let mut interval = tokio::time::interval(dur);
tokio::spawn(async move {
// first tick is at 0ms
interval.tick().await;
loop {
interval.tick().await;
tokio::spawn(f());
}
});
}
This works fine until it's called from inside a class:
fn main() {}
struct Foo {}
impl Foo {
fn bar(&self) {
set_interval(|| self.task(), Duration::from_millis(1000));
}
async fn task(&self) {
}
}
self is not 'static, and we can't restrict lifetime parameter to something that is less than 'static because of tokio::task.
Is it possible to modify set_interval implementation so it works in cases like this?
Link to playground
P.S. Tried to
let instance = self.clone();
set_interval(move || instance.task(), Duration::from_millis(1000));
but I also get an error: error: captured variable cannot escape FnMut closure body
Is it possible to modify set_interval implementation so it works in cases like this?
Not really. Though spawn-ing f() really doesn't help either, as it precludes a simple "callback owns the object" solution (as you need either both callback and future to own the object, or just future).
I think that leaves two solutions:
Convert everything to shared mutability Arc, the callback owns one Arc, then on each tick it clones that and moves the clone into the future (the task method).
Have the future (task) acquire the object from some external source instead of being called on one, this way the intermediate callback doesn't need to do anything. Or the callback can do the acquiring and move that into the future, same diff.
Incidentally at this point it could make sense to just create the future directly, but allow cloning it. So instead of taking a callback set_interval would take a clonable future, and it would spawn() clones of its stored future instead of creating them anew.
As mentioned by #Masklinn, you can clone the Arc to allow for this. Note that cloning the Arc will not clone the underlying data, just the pointer, so it is generally OK to do so, and should not have a major impact on performance.
Here is an example. The following code will produce the error async block may outlive the current function, but it borrows data, which is owned by the current function:
fn main() {
// 🛑 Error: async block may outlive the current function, but it borrows data, which is owned by the current function
let data = Arc::new("Hello, World".to_string());
tokio::task::spawn(async {
println!("1: {}", data.len());
});
tokio::task::spawn(async {
println!("2: {}", data.len());
});
}
Rust unhelpfully suggests adding move to both async blocks, but that will result in a borrowing error because there would be multiple ownership.
To fix the problem, we can clone the Arc for each task and then add the move keyword to the async blocks:
fn main() {
let data = Arc::new("Hello, World".to_string());
let data_for_task_1 = data.clone();
tokio::task::spawn(async move {
println!("1: {}", data_for_task_1.len());
});
let data_for_task_2 = data.clone();
tokio::task::spawn(async move {
println!("2: {}", data_for_task_2.len());
});
}

How to set the value of a struct inside a GTK event in rust?

How to set the value of a struct inside a GTK event in rust?
I'm gettting an error when trying to modify the s struct instance below.
use gtk::prelude::*;
use gio::prelude::*;
use gtk::{Application, ApplicationWindow, Button};
struct SomeStruct {
val: bool,
}
fn main() {
let mut s = SomeStruct {
val: false,
};
application.connect_activate(|app| {
let window = ApplicationWindow::new(app);
window.set_title("test");
window.set_default_size(350,70);
let button = Button::with_label("Test");
button.connect_clicked(|_|{
s.val = true; // error here
});
window.add(&button);
window.show_all();
});
application.run(&[]);
}
Error messages:
error[E0597]: `s` does not live long enough
error[E0596]: cannot borrow `s` as mutable, as it is a captured variable in a `Fn` closure
Your code has two issues:
Although s outlives the GTK application, Rust doesn't know that, whis is why it complains of s not living long enough.
ButtonExt::connect_clicked() accepts a Fn, so it's not allowed to mutate data without extra precautions.
The first issue can be fixed by allocating s on the heap and accessing it through a reference-counted pointer, which ensures that the object lives at least as long as the closure that refers to it.
The second issue is easiest to resolve through interior mutability, by wrapping SomeStruct into a RefCell. RefCell holds a value and allows the holder to mutate it through a shared reference to the RefCell. When requesting a mut reference to the inner value, RefCell will check at run-time that no other reference to the value is still live. (This could happen if your closure were to get access to the value and then, while holding the value, called another closure that does the same.)
Those two combined would lead to code like this (untested):
use std::rc::Rc;
use std::cell::RefCell;
fn main() {
let s = Rc::new(RefCell::new(SomeStruct { val: false }));
application.connect_activate(|app| {
let window = ApplicationWindow::new(app);
window.set_title("test");
window.set_default_size(350, 70);
let button = Button::with_label("Test");
// clone the handle to s and move it into the closure
let s2 = Rc::clone(&s);
button.connect_clicked(move |_| {
s2.borrow_mut().val = true;
});
window.add(&button);
window.show_all();
});
application.run(&[]);
}

How to join thread in drop function? [duplicate]

I want to create a thread inside of the new method and stop it after the struct is destroyed:
use std::thread;
struct Foo {
handle: thread::JoinHandle<()>,
}
impl Foo {
pub fn new(name: &str) -> Foo {
let name = name.to_string();
Foo {
handle: thread::spawn(move || {
println!("hi {}", name);
}),
}
}
pub fn stop(&mut self) {
self.handle.join();
}
}
fn main() {
let mut foo = Foo::new("test");
foo.stop();
}
This doesn't compile, and I can not understand why:
error[E0507]: cannot move out of borrowed content
--> <anon>:15:9
|
15 | self.handle.join();
| ^^^^ cannot move out of borrowed content
And in newer versions of Rust:
error[E0507]: cannot move out of `self.handle` which is behind a mutable reference
--> src/main.rs:17:9
|
17 | self.handle.join();
| ^^^^^^^^^^^ move occurs because `self.handle` has type `std::thread::JoinHandle<()>`, which does not implement the `Copy` trait
How can I fix this error?
In the future, I will implement Drop for Foo, and will call stop() from drop().
The function signature of JoinHandle::join is:
fn join(self) -> Result<T>
This means that the method takes self (the receiver object) by values (taking the ownership/consuming it). But you only have a borrow to your JoinHandle; a mutable one, but still merely a borrow, not the ownership. Thus you can't call this method, because you can't move the ownership out of your borrow into this join() method.
An easy way to fix that, is by accepting self by value in the stop() method, too:
pub fn stop(self) {
self.handle.join();
}
But you will notice that this isn't possible when implementing Drop, because drop() has the signature fn drop(&mut self)! Bummer! But there is a little trick you can use, described below. Please be aware that joining threads in drop() is probably not a good idea! Read Matthieu M.'s answer for more information on that!
If you still think, for whatever reason, that you really want to join a thread in drop(), you can store the JoinHandle in an Option<T> to save whether or not it's already joined. If you have a Some(T) you can obtain a T (by value!) from it by using the method Option::take(). Then you can write:
fn drop(&mut self) {
// `self.handle` has the type `Option<JoinHandle<()>>` here!
if let Some(handle) = self.handle.take() {
handle.join().expect("failed to join thread");
}
}
Don't.
It may seem counter-intuitive, but joining a thread (or process) in a destructor is generally a bad idea.
Note that asking to join does not cause the thread to stop by itself; it's just about waiting for the thread to stop, and the thread may not. There are multiple reasons why this could happen:
the handle being on the same thread as the one it controls,
the thread to be stopped waiting on a channel the current thread should send a signal on,
...
Yes, that's a deadlock. An implicit deadlock.
A particular nasty situation is if your current thread panics (something unforeseen occurred). Unwinding starts... and blocks! And all the resources that this thread was supposed to clean-up hung in limbo, forever.
A better design is to instead create an explicit join method, which consume self (by value). It also lets you return a Result, in case joining causes an error.
And in order for your users to remember to join explicitly, panic! in the Drop implementation if they forgot to.
That is:
impl Foo {
fn join(mut self) -> std::thread::Result<()> {
match self.handle.take() {
Some(h) => h.join(),
None => Ok(()),
}
}
}
impl Drop for Foo {
fn drop(&mut self) {
if self.handle.is_some() {
panic!("You MUST call either join on `Foo` to clean it up.");
}
}
}
Note: I am aware that panicking in destructors is controversial, however it is much safer to abort a process when it's in an unknown state that go on and hope for the best.
If you really, despite my warning, want to shoot yourself in the foot, join in drop.
The problem in join signature:
fn join(self) -> Result<T>
so to fix your code, you need something like:
pub fn stop(self) {
self.handle.join();
}
If you don't mind unsafe code, then here's something you could do (please look at Matthieus answer why this can be a bad idea).
struct Foo {
handle: ManuallyDrop<thread::JoinHandle<()>>,
}
impl Drop for Foo {
fn drop(&mut self) {
unsafe {
let _ = ManuallyDrop::take(&mut self.handle).join();
}
}
}

Joining a thread in a method that takes `&mut self` (like drop) results in "cannot move out of borrowed content"

I want to create a thread inside of the new method and stop it after the struct is destroyed:
use std::thread;
struct Foo {
handle: thread::JoinHandle<()>,
}
impl Foo {
pub fn new(name: &str) -> Foo {
let name = name.to_string();
Foo {
handle: thread::spawn(move || {
println!("hi {}", name);
}),
}
}
pub fn stop(&mut self) {
self.handle.join();
}
}
fn main() {
let mut foo = Foo::new("test");
foo.stop();
}
This doesn't compile, and I can not understand why:
error[E0507]: cannot move out of borrowed content
--> <anon>:15:9
|
15 | self.handle.join();
| ^^^^ cannot move out of borrowed content
And in newer versions of Rust:
error[E0507]: cannot move out of `self.handle` which is behind a mutable reference
--> src/main.rs:17:9
|
17 | self.handle.join();
| ^^^^^^^^^^^ move occurs because `self.handle` has type `std::thread::JoinHandle<()>`, which does not implement the `Copy` trait
How can I fix this error?
In the future, I will implement Drop for Foo, and will call stop() from drop().
The function signature of JoinHandle::join is:
fn join(self) -> Result<T>
This means that the method takes self (the receiver object) by values (taking the ownership/consuming it). But you only have a borrow to your JoinHandle; a mutable one, but still merely a borrow, not the ownership. Thus you can't call this method, because you can't move the ownership out of your borrow into this join() method.
An easy way to fix that, is by accepting self by value in the stop() method, too:
pub fn stop(self) {
self.handle.join();
}
But you will notice that this isn't possible when implementing Drop, because drop() has the signature fn drop(&mut self)! Bummer! But there is a little trick you can use, described below. Please be aware that joining threads in drop() is probably not a good idea! Read Matthieu M.'s answer for more information on that!
If you still think, for whatever reason, that you really want to join a thread in drop(), you can store the JoinHandle in an Option<T> to save whether or not it's already joined. If you have a Some(T) you can obtain a T (by value!) from it by using the method Option::take(). Then you can write:
fn drop(&mut self) {
// `self.handle` has the type `Option<JoinHandle<()>>` here!
if let Some(handle) = self.handle.take() {
handle.join().expect("failed to join thread");
}
}
Don't.
It may seem counter-intuitive, but joining a thread (or process) in a destructor is generally a bad idea.
Note that asking to join does not cause the thread to stop by itself; it's just about waiting for the thread to stop, and the thread may not. There are multiple reasons why this could happen:
the handle being on the same thread as the one it controls,
the thread to be stopped waiting on a channel the current thread should send a signal on,
...
Yes, that's a deadlock. An implicit deadlock.
A particular nasty situation is if your current thread panics (something unforeseen occurred). Unwinding starts... and blocks! And all the resources that this thread was supposed to clean-up hung in limbo, forever.
A better design is to instead create an explicit join method, which consume self (by value). It also lets you return a Result, in case joining causes an error.
And in order for your users to remember to join explicitly, panic! in the Drop implementation if they forgot to.
That is:
impl Foo {
fn join(mut self) -> std::thread::Result<()> {
match self.handle.take() {
Some(h) => h.join(),
None => Ok(()),
}
}
}
impl Drop for Foo {
fn drop(&mut self) {
if self.handle.is_some() {
panic!("You MUST call either join on `Foo` to clean it up.");
}
}
}
Note: I am aware that panicking in destructors is controversial, however it is much safer to abort a process when it's in an unknown state that go on and hope for the best.
If you really, despite my warning, want to shoot yourself in the foot, join in drop.
The problem in join signature:
fn join(self) -> Result<T>
so to fix your code, you need something like:
pub fn stop(self) {
self.handle.join();
}
If you don't mind unsafe code, then here's something you could do (please look at Matthieus answer why this can be a bad idea).
struct Foo {
handle: ManuallyDrop<thread::JoinHandle<()>>,
}
impl Drop for Foo {
fn drop(&mut self) {
unsafe {
let _ = ManuallyDrop::take(&mut self.handle).join();
}
}
}

Copying a struct for use on another thread

I have a struct:
struct MyData {
x: i32
}
I want to asynchronously start a long operation on this struct.
My first attempt was this:
fn foo(&self) { //should return immediately
std::thread::Thread::spawn(move || {
println!("{:?}",self.x); //consider a very long operation
});
}
Clearly the compiler cannot infer an appropriate lifetime due to conflicting requirements because self may be on the stack frame and thus cannot be guaranteed to exist by the time the operation is running on a different stack frame.
To solve this, I attempted to make a copy of self and provide that copy to the new thread:
fn foo(&self) { //should return immediately
let clone = self.clone();
std::thread::Thread::spawn(move || {
println!("{:?}",clone.x); //consider a very long operation
});
}
I think that does not compile because now clone is on the stack frame which is similar to before. I also tried to do the clone inside the thread, and that does not compile either, I think for similar reasons.
Then I decided maybe I could use a channel to push the copied data into the thread, on the theory that perhaps channel can magically move (copy?) stack-allocated data between threads, which is suggested by this example in the documentation. However the compiler cannot infer a lifetime for this either:
fn foo(&self) { //should return immediately
let (tx, rx) = std::sync::mpsc::channel();
tx.send(self.clone());
std::thread::Thread::spawn(move || {
println!("{:?}",rx.recv().unwrap().x); //consider a very long operation
});
}
Finally, I decided to just copy my struct onto the heap explicitly, and pass an Arc into the thread. But not even here can the compiler figure out a lifetime:
fn foo(&self) { //should return immediately
let arc = std::sync::Arc::new(self.clone());
std::thread::Thread::spawn(move || {
println!("{:?}",arc.clone().x); //consider a very long operation
});
}
Okay borrow checker, I give up. How do I get a copy of self onto my new thread?
I think your issue is simply because your structure does not derive the Clone trait. You can get your second example to compile and run by adding a #[derive(Clone)] before your struct's definition.
What I don't understand in the compiler behaviour here is what .clone() function it tried to use here. Your structure indeed did not implement the Clone trait so should not by default have a .clone() function.
playpen
You may also want to consider in your function taking self by value, and let your caller decide whether it should make a clone, or just a move.
As an alternative solution, you could use thread::scoped and maintain a handle to the thread. This allows the thread to hold a reference, without the need to copy it in:
#![feature(old_io,std_misc)]
use std::thread::{self,JoinGuard};
use std::old_io::timer;
use std::time::duration::Duration;
struct MyData {
x: i32,
}
// returns immediately
impl MyData {
fn foo(&self) -> JoinGuard<()> {
thread::scoped(move || {
timer::sleep(Duration::milliseconds(300));
println!("{:?}", self.x); //consider a very long operation
timer::sleep(Duration::milliseconds(300));
})
}
}
fn main() {
let d = MyData { x: 42 };
let _thread = d.foo();
println!("I'm so fast!");
}

Resources