I'm writing a program that will concurrently call an API and fill a VecDeque with integers from the response JSON. Since these will be running concurrently, I wrapped the VecDeque in a Mutex. When I test the code and try to push an integer into the VecDeque, I get an error.
#[tokio::main]
async fn main() -> Result<(), ()> {
let client = Client::new();
let mut tank = Mutex::new(VecDeque::new());
// let mut tank = VecDeque::with_capacity(10);
tank.push_back(2);
tank.push_back(3);
println!("{:?}", tank);
Ok(())
}
tank.push_back(2);
^^^^^^^^^ method not found in `std::sync::Mutex<VecDeque<_>>
Do I need to create the VecDeque inside a struct instead?
As per the suggestion, I needed to lock before changing the VecDeque. It works now:
#[tokio::main]
async fn main() -> Result<(), ()> {
let client = Client::new();
let mut tank = Mutex::new(VecDeque::new());
let mut tank = tank.lock().unwrap().push_back(2);
let mut tank = tank.lock().unwrap().push_back(3);
println!("{:?}", tank);
Ok(())
}
Related
I've been trying to separate all my Redis operations in a separate implementation, but I got this error when I passed the Redis reference to the implementation.
error[E0596]: cannot borrow `*self.redis_client` as mutable, as it is behind a `&` reference
--> src/main.rs:30:21
|
30 | let _: () = self.redis_client.set("key", "value").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
Code:
use redis::{Commands};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let redis_client_uri = String::from("redis://127.0.0.1:6379");
let redis_client = redis::Client::open(redis_client_uri)?;
let mut redis = redis_client
.get_connection()
.expect("Failed to connect redis");
let batch = vec!["Sample value".to_string()];
CacheOperations::new(&redis, batch);
Ok(())
}
struct CacheOperations<'a> {
redis_client: &'a redis::Connection,
batch: Vec<String>,
}
impl<'a> CacheOperations<'a> {
fn new(redis_client: &'a redis::Connection, batch: Vec<String>) -> Self {
Self {
redis_client: &redis_client,
batch: batch,
}
}
fn insert_batch(self) {
let _: () = self.redis_client.set("key", "value").unwrap();
}
}
You just need to use the mut keyword to indicate that a reference or value is mutable. When you use it with a lifetime, the mut goes after the lifetime usage (Ex: &'abc mut x).
use redis::{Commands};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let redis_client_uri = String::from("redis://127.0.0.1:6379");
let redis_client = redis::Client::open(redis_client_uri)?;
let mut redis = redis_client
.get_connection()
.expect("Failed to connect redis");
let batch = vec!["Sample value".to_string()];
// Use a mutable reference when creating the CacheOperations
CacheOperations::new(&mut redis, batch);
Ok(())
}
struct CacheOperations<'a> {
// Store a mutable reference
redis_client: &'a mut redis::Connection,
batch: Vec<String>,
}
impl<'a> CacheOperations<'a> {
// We need to consume a mutable reference
fn new(redis_client: &'a mut redis::Connection, batch: Vec<String>) -> Self {
// No need to reference the reference, we can store it as-is
Self { redis_client, batch }
}
// While not required here, you can use mut self to state that self is mutable
// when a function consumes self as an owned value.
fn insert_batch(mut self) {
let _: () = self.redis_client.set("key", "value").unwrap();
}
}
I am trying to write a tcp server with async-std, in order to resolve the confilice of read-write borrow check, I found a strange way:
use async_std::prelude::*;
use async_std::task;
use async_std::net::TcpListener;
use async_std::io::BufReader;
fn main() {
task::block_on(async {
let listener = TcpListener::bind("0.0.0.0:9000").await.unwrap();
let mut incoming = listener.incoming();
while let Some(stream) = incoming.next().await {
let stream = stream.unwrap();
println!("Client Addr: {:?}", stream.peer_addr().unwrap());
task::spawn( async move {
let (reader, mut writer) = (&stream, &stream); // Stange here <-----
let reader = BufReader::new(reader);
let mut lines = reader.lines();
while let Some(line) = lines.next().await {
let mut line = line.unwrap();
line.push('x');
line.push('\n');
writer.write_all(line.as_bytes()).await.unwrap();
}
});
}
});
}
Strange:
let (reader, mut writer) = (&stream, &stream); // Stange here <-----
I wrote a verification program following this method:
fn main() {
let mut arr = vec![1, 2, 3, 4];
let (r, mut w) = (&arr, &arr);
for v in r.iter() {
if v == &2 {
w.push(5);
}
}
dbg!(arr);
}
got error:
error[E0596]: cannot borrow `*w` as mutable, as it is behind a `&` reference
can anyone explain it ?
This works because TcpStream has the following impls:
impl Read for TcpStream
impl Write for TcpStream
impl<'_> Read for &'_ TcpStream
impl<'_> Write for &'_ TcpStream
The first two are the "normal" ones, the last two are the "special" ones that allow you to do this reader/writer trick.
For example: The read() trait method is defined like this:
pub fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ImplFuture<Result<usize>>
When you do stream.read(buf), you're using the impl Read for TcpStream impl. Therefore, you're calling the method with self being of type &mut TcpStream.
When you do let reader = &stream; reader.read(buf), you're using the impl<'_> Read for &'_ TcpStream. Therefore, you're calling the method with self being of type &mut &TcpStream.
I am trying to use the read and write of a tcp stream in different threads. This is what I currently have:
use tokio::prelude::*;
use tokio::net::TcpStream;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut stream = TcpStream::connect("localhost:8080").await?;
let (mut read, mut write) = stream.split();
tokio::spawn(async move {
loop {
let mut buf = [0u8; 32];
read.read(&mut buf).await.unwrap();
println!("{}", std::str::from_utf8(&buf));
}
});
Ok(())
}
Im going to use another thread for the write. My problem is that I get the error that 'stream' is dropped while still borrowed.
That happens due to the method signature of Tokio::split, as you can see it takes &mut self, so its part cannot be used in a tokio::spawn future argument due to the 'static bound. So, this is exactly what the error says.
What you are searching is tokio::io::split. Playground
use tokio::prelude::*;
use tokio::net::TcpStream;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut stream = TcpStream::connect("localhost:8080").await?;
let (mut read, mut write) = tokio::io::split(stream);
tokio::spawn(async move {
loop {
let mut buf = [0u8; 32];
read.read(&mut buf).await.unwrap();
println!("{:?}", std::str::from_utf8(&buf));
}
});
Ok(())
}
Reading https://users.rust-lang.org/t/why-i-have-to-use-tokio-tcpstream-split-for-concurrent-read-writes/47755/3
And it suggests to use into_split it is more efficient.
tokio::io::split uses a Mutex which into_split apparently does not have (specific to TcpStream)
I want to modify a big vector from multiple threads in parallel.
Works fine: u32
use std::thread;
use std::sync::Arc;
fn main() {
let input = Arc::new([1u32, 2, 3, 4]);
let mut handles = Vec::new();
for t in 0..4 {
let inp = input.clone();
let handle = thread::spawn(move || unsafe {
let p = (inp.as_ptr() as *mut u32).offset(t as isize);
*p = inp[t] + t as u32 ;
});
handles.push(handle);
}
for h in handles {
h.join().unwrap();
}
println!("{:?}", input);
}
Segfaults: Vec<HashSet<&str>>
When I change the u32 to Vec<HashSet<&str>>, the pointer does not seem to work.
use std::thread;
use std::sync::Arc;
use std::collections::HashSet;
fn main() {
let mut a = HashSet::new();
a.insert("aaa");
let input = Arc::new(vec![a.clone(), a.clone(), a.clone(), a.clone()]);
let mut handles = Vec::new();
for _t in 0..4 {
let inp = input.clone();
let handle = thread::spawn(move || unsafe {
let p = (inp.as_ptr() as *mut Vec<HashSet<&str>>).offset(0);
(*p)[0].insert("bbb");
});
handles.push(handle);
}
for h in handles {
h.join().unwrap();
}
println!("{:?}", input);
}
What is the difference?
It is hard to say what is wrong with your initial code as it segfaults in the playground. You are likely invoking undefined behavior by taking a reference to immutable (!) vec and trying to mutate its elements by casting &Vec -> *mut Vec -> &mut Vec (on a method call). Multiple mutable references to the same thing are a big no-no. Besides, your code even uses the same HashSet ((*p)[0]) mutably in parallel, which, again, is undefined behavior.
The easiest way here would be to use crossbeam's scoped threads. They allow referencing stack variables, like your input. Vec can also give out distinct mutable references to its elements without using unsafe. Using this, your code seems to do the expected thing.
use crossbeam::thread;
use std::collections::HashSet;
fn main() {
let mut a = HashSet::new();
a.insert("aaa");
let mut input = vec![a.clone(), a.clone(), a.clone(), a.clone()];
thread::scope(|s| {
for set in &mut input {
s.spawn(move |_| {
set.insert("bbb");
});
}
}).unwrap();
println!("{:?}", input);
}
I have found the way:
use std::thread;
use std::sync::Arc;
use std::collections::HashSet;
fn main() {
let mut a = HashSet::new();
a.insert("aaa");
let input = Arc::new(vec![a.clone(), a.clone(), a.clone(), a.clone()]);
let mut handles = Vec::new();
for _t in 0..4 {
let inp = input.clone();
//let out = output.clone();
let handle = thread::spawn(move || unsafe {
let p = (inp.as_ptr() as *mut Vec<HashSet<&str>>).offset(0);
(*p)[0].insert("bbb");
});
handles.push(handle);
}
for h in handles {
h.join().unwrap();
}
println!("{:?}", input);
}
thanks for guys!
I am trying to read all content from a file into a vector using the async rust api:
let mut content : Vec<u8> = vec![];
let f = tokio::fs::File::open("myfilecontent")
.and_then(|mut myfile| {
myfile.read_buf(&mut content)
});
f.await;
But I keep getting this error:
error[E0515]: cannot return value referencing function parameter `myfile`
Which sounds reasonable, because the future returned by the closure must keep a reference to the file, but as this closure is the only user of the file it could take ownership. How can I convince rust to do the right thing?
You can use an async move block like so:
use futures::TryFutureExt;
use tokio::io::AsyncReadExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut content: Vec<u8> = vec![];
let f = tokio::fs::File::open("myfilecontent").and_then(
|mut myfile| async move { myfile.read_buf(&mut content).await },
);
f.await?;
Ok(())
}
or skip and_then and go straight for .await:
use tokio::io::AsyncReadExt;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut content: Vec<u8> = vec![];
let mut myfile = tokio::fs::File::open("myfilecontent").await?;
myfile.read_buf(&mut content).await?;
Ok(())
}