Print updated value before it should update - multithreading

Here's a short code
use std::{thread, time::{Duration}, sync::{Arc, Mutex}};
fn main() {
let num = Arc::new(Mutex::new(0u8));
let clone = num.clone();
thread::spawn(move || {
loop {
println!("{:?};", *num.lock().unwrap()); // always prints 0
thread::sleep(Duration::from_secs(1));
*num.lock().unwrap() = 0;
println!("{:?};", *num.lock().unwrap()); // always prints 0
}
});
listen(clone);
}
fn listen(num: Arc<Mutex<u8>>) {
rdev::listen(move |event| {
match event.event_type {
rdev::EventType::KeyPress(_) => {
*num.lock().unwrap() += 1;
},
_ => {},
}
}).unwrap();
}
All it should do is just counting how many times the users pressed any key on a keyboard. But this code is doesn't work.
I added 2 println! statements - before the value is updated and after that. And I assume to get a real value in the first statement and 0 in the second one. But for some reason both println! print a zero.
Why so and how can I avoid it?
The code does work if I don't reset value to a zero. But I have to do it.

It seems that you leave no time between the num read and write. So it writes the num value and immediatly read from it.
You probably want to add an extra delay statement:
loop {
println!("{:?};", *num.lock().unwrap());
thread::sleep(Duration::from_secs(1));
*num.lock().unwrap() = 0;
println!("{:?};", *num.lock().unwrap());
//this delay will allow the other thread to modify the num before the read happens.
thread::sleep(Duration::from_secs(1));
}

Related

Yew: Difficulty with nested callbacks

I'm attempting to do something that I feel is pretty basic: I have a pulldown, and I'd like the onchange event for that pulldown to cause the program to fetch some data from the backend based on the user's input. (And then, you know, give the user more options based on the first thing they picked. Really simple, and seems like I ought to have been able to find an easy way to do this.)
Full code for this minimal (failing) example is at: https://github.com/djmcmath/broken-yew
But the relevant bit, which doesn't behave correctly, is below:
The view function renders, delightfully, an iterated list. I pass in a callback, so it knows what to do on the "onchange" event.
The callback gets executed, which makes me very happy. But it isn't calling the Msg::GetData. This compiles, which is nice, but it doesn't work, which is less nice.
I've spent, I'm ashamed to admit, several weeks of my spare time fighting with this. I think it has something to do with scopes and lifetimes. I think that the way I'm making this compile -- by cloning the context and using "move" disconnects it from the actual context that I need to make this work. But every variation on the theme that I've been able to find in examples and references complains about scope or lifetimes.
Thanks in advance for the help.
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::GetData(value) => {
log::info!("Start 'fetch' with user-selected value: {}", value);
ctx.link().send_future(async {
match fetch_markdown("url_shortened_for_clarity").await {
Ok(md) => Msg::SetMarkdownFetchState(FetchState::Success(md)),
Err(err) => Msg::SetMarkdownFetchState(FetchState::Failed(err)),
}
});
false
},
Msg::SetMarkdownFetchState(fetch_state) => {
let mut wr = WebReturn { term_id: 0, dow: 0, dep_time_num: 0 };
match fetch_state {
FetchState::Success(s) => { wr = serde_json::from_str(&s).expect(&format!("Poorly formatted JSON! {}", s).to_string()); },
FetchState::Failed(f) => { log::info!("Fetch failed: {}", f); },
FetchState::NotFetching => {},
FetchState::Fetching => {}
};
log::info!("term_id (3) : {}, dep_time_num (12000) : {}, and dow (3) : {}", wr.term_id, wr.dep_time_num, wr.dow);
true
}
}
}
fn view(&self, ctx:&Context<Self>) -> Html {
let ctx_link = ctx.link().clone();
let my_callback: Callback<String> = Callback::from(move |value: String| {
let val_as_num = value.parse::<i32>().unwrap_or(0);
log::info!("Returned value: {}", val_as_num);
ctx_link.callback(|val_as_num: i32| Msg::GetData(val_as_num));
});
html! {
<div>
{ self.render_list(&self.props.term_list, my_callback) }
</div>
}
}
This line does not "call back" to your component, it creates a callback and then doesn't call it:
ctx_link.callback(|val_as_num: i32| Msg::GetData(val_as_num));
You need to instead call .send_message() in your callback or, better yet, create your original callback with .callback():
let my_callback = ctx_link.callback(|value: String| {
let val_as_num = value.parse::<i32>().unwrap_or(0);
log::info!("Returned value: {}", val_as_num);
Msg::GetData(val_as_num)
});

While let does not stop even when the while's condition is fulfilled

I'm new to rust, and I'm trying to code a program that opens a websocket for 10 seconds, receive the data from it and then stops. The piece of code is the following.
let now = Instant::now();
while let n=now.elapsed().as_secs() < 10 {
let msg = socket.read_message().expect("Error reading message");
let msg = match msg {
tungstenite::Message::Text(s) => { s }
_ => { panic!() }
};
let parsed: serde_json::Value = serde_json::from_str(&msg).expect("Can't parse to JSON");
let price_str=parsed["p"].as_str().unwrap();
let price: f32 = price_str.parse().unwrap();
write!(f,"1 \t").expect("unable to write");
write!(f, "\t\t {} \n", price).expect("unable to write");
println!("{}",n);
}
n becomes false after 10 seconds, but the loop never ends. What I'm doing wrong?
Thanks for your help.
while let n binds the result of the expression now.elapsed().as_secs() < 10 to n. This binding can never fail, thus your loop never exits.
The compiler emits a lint to prevent such mistakes:
warning: irrefutable `while let` pattern
--> src/lib.rs:24:11
|
24 | while let n = now.elapsed().as_secs() < 10 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(irrefutable_let_patterns)]` on by default
= note: this pattern will always match, so the loop will never exit
= help: consider instead using a `loop { ... }` with a `let` inside it
To fix your snippet, you'll need to remove the let n part. Or in a more unusual and rather unidiomatic manner, you can pattern match on the value returned by now.elapsed().as_secs() < 10 through:
while let true = now.elapsed().as_secs() < 10 {
// do your thing
}
If you want access to the loop control variable, you can still bind it to a variable through:
let now = std::time::Instant::now();
while let n # true = now.elapsed().as_secs() < 10 {
println!("loop_control={}", n)
}
As #Jmb mentions in a comment, there is another issue that's not a compiler error: The loop body may block indefinitely, thus rendering the timeout ineffective.

Check if the lines of a file contains given pattern without regex in Rust

I'll start by saying I'm new to rust. Actually, this is the first Rust program I'm trying to write.
I'm able to read a (large) file line by line and check which lines contain the pattern "PerfectSwitch-0 : Message:" with the following code:
use std::fs::File;
use std::io::{self, prelude::*, BufReader};
fn main() -> io::Result<()>{
let file = File::open("../test.out")?;
let reader = BufReader::new(file);
for line in reader.lines(){
let line = line.unwrap();
if line.contains("PerfectSwitch-0: Message:"){
println!("{}", line);
}
}
Ok(())
}
However, what I really want to do is to modify this code in a way that my pattern could match "PerfectSwitch-0 : Message:", "PerfectSwitch-1 : Message:", "PerfectSwitch-2 : Message:", ..., "PerfectSwitch-8 : Message:" and "PerfectSwitch-9 : Message:", without a regex.
The reason for this is that I think using regex in this case would be a little bit of a overkill and it could slow down my program (?).
I've tried writing if line.contains("PerfectSwitch-?: Message:") but, non-surprisingly, it didn't work.
Does anyone know if this is possible?
Thanks
I would try regex in this case and see if it meets your performance requirements first.
One upside in my opinion is that regex is easier to parse and change around when you come to revisit the code.
For example, given the following input to parse:
let input = vec![
"PerfectSwitch-42 : Message:",
"PerfectSwitch- : Message:",
"Message :",
"PerfectSwitch-271828 : Message:",
"PerfectSwitch-314159 : Message:",
"PerfectSwitch-",
];
We could do the following:
use regex::Regex;
fn main() {
let re = Regex::new(r"^PerfectSwitch-[0-9]+ : Message:").unwrap();
let result = input
.iter()
.filter(|&s| re.is_match(&s))
.collect::<Vec<_>>();
}
Or write a gnarly handwritten solution:
fn contains_switch(s: &str) -> bool {
let mut cursor = 0;
// Return early if the string is not at least as long as:
// - The length of "PerfectSwitch-" (14)
// - One or more ASCII digit(s) (1..)
// - One ASCII whitespace (1)
// - The length of ": Message:" (10)
if s.len() < 26 {
return false;
}
// Match on and consume "PerfectSwitch-"
if &s[..14] != "PerfectSwitch-" {
return false;
}
cursor += 14;
// Match on and consume ASCII digits
let digits = s[cursor..].bytes().take_while(u8::is_ascii_digit).count();
if digits == 0 {
return false;
}
cursor += digits;
// Match on and consume ASCII whitespace
if &s[cursor..cursor + 1] != " " {
return false;
}
cursor += 1;
// Match on and consume ": Message:"
if s.len() < cursor + 10 {
return false;
}
&s[cursor..cursor + 10] == ": Message:"
}
fn main() {
let result = input
.iter()
.filter(|&s| contains_switch(s))
.collect::<Vec<_>>();
}
I'd wager that the first is less likely to contain a bug.
In both cases this should give you:
[
"PerfectSwitch-42 : Message:",
"PerfectSwitch-271828 : Message:",
"PerfectSwitch-314159 : Message:",
]
Benchmark
Iterating over 1,000,000 randomly generated lines, benchmarked with glassbench, we get the following:
┌─┬───────────────┬──────────────┬─────────────┐
│#│ task │total duration│mean duration│
├─┼───────────────┼──────────────┼─────────────┤
│1│re_is_match │ 2.641099049s│ 52.82198ms│
│2│contains_switch│ 1.999254015s│ 7.37732ms│
└─┴───────────────┴──────────────┴─────────────┘
With the above results, and the trade-off in maintain- and readability, I would really opt for using the regex crate.
You can loop over all possible values:
let line = line.unwrap();
for i in 0..=9 {
if line.contains(&format!("PerfectSwitch-{}: Message:", i)) {
println!("{}", line);
}
}
Although you probably want to rethink your assumption that regexes are bad. Rust's regex library is very fast, and I doubt any small performance gains you get here will outweigh the lack of maintainability that comes with rolling your own parsing code.

wbkgd does not set background color

I'm using Rust to write an ncurses app.
I'm trying to set the color of a subwin, however having no success. I'm not even sure the window is created in the first place, or it just doesn't want to set the color.
Here's a minimal example:
use ncurses::*;
fn main() {
setlocale(LcCategory::all, "");
initscr();
keypad(stdscr(), true);
start_color();
init_pair(1, COLOR_RED, COLOR_RED);
loop {
let user_input = get_wch();
match user_input.unwrap() {
WchResult::Char(ch) => {
match ch {
27 => break,
_ => {}
}
},
WchResult::KeyCode(code) => {
match code {
KEY_F5 => {
let ln = subwin(stdscr(), LINES(), 5, 0, 0);
wbkgd(ln, COLOR_PAIR(1));
refresh();
},
_ => {}
}
}
}
}
endwin();
}
As you can see, I initialized a color pair and invoked start_colors().
What could be the issue?
I think the problem might be that your not refreshing the sub-window. Try using wrefresh(ln) instead. Actually use both refresh and refresh(ln).
In this chunk
let ln = subwin(stdscr(), LINES(), 5, 0, 0);
wbkgd(ln, COLOR_PAIR(1));
refresh();
the refresh overwrites the result from the subwin. Also, you would get better results by ORing the COLOR_PAIR with a space (see this).
Addressing the comments:
let user_input = get_wch();
also does a refresh (overwriting the result from the subwin).

Why is this hashmap search slower than expected?

What is the best way to check a hash map for a key?
Currently I am using this:
let hashmap = HashMap::<&str, &str>::new(); // Empty hashmap
let name = "random";
for i in 0..5000000 {
if !hashmap.contains_key(&name) {
// Do nothing
}
}
This seems to be fast in most cases and takes 0.06 seconds when run as shown, but when I use it in this following loop it becomes very slow and takes almost 1 min on my machine. (This is compiling with cargo run --release).
The code aims to open an external program, and loop over the output from that program.
let a = vec!["view", "-h"]; // Arguments to open process with
let mut child = Command::new("samtools").args(&a)
.stdout(Stdio::piped())
.spawn()
.unwrap();
let collect_pairs = HashMap::<&str, &str>::new();
if let Some(ref mut stdout) = child.stdout {
for line in BufReader::new(stdout).lines() {
// Do stuff here
let name = "random";
if !collect_pairs.contains_key(&name) {
// Do nothing
}
}
}
For some reason adding the if !collect_pairs.contains_key( line increases the run time by almost a minute. The output from child is around 5 million lines. All this code exists in fn main()
EDIT
This appears to fix the problem, resulting in a fast run time, but I do not know why the !hashmap.contains_key does not work well here:
let n: Option<&&str> = collect_pairs.get(name);
if match n {Some(v) => 1, None => 0} == 1 {
// Do something
}
One thing to consider is that HashMap<K, V> uses a cryptographically secure hashing algorithm by default, so it will always be a bit slow by nature.
get() boils down to
self.search(k).map(|bucket| bucket.into_refs().1)
contains_key is
self.search(k).is_some()
As such, that get() is faster for you seems strange to me, it's doing more work!
Also,
if match n {Some(v) => 1, None => 0} == 1 {
This can be written more idiomatically as
if let Some(v) = n {
Ive found my problem, Im sorry I didnt pick up until now. I wasnt checking the return of if !collect_pairs.contains_key(&name) properly. It returns true for some reason resulting in the rest of the if block being run. I assumed it was evaluating to false. Thanks for the help

Resources