Fltk channel receiver misses some messages - rust

I create an fltk window with a button. When clicked, the button spawns a thread with 10 iterations inside. Each iteration sends a message to the channel. With println!() everything works fine, but if I delete it - the channel starts skipping some messages.
[dependencies]
fltk = { version="1.2.23", features=["fltk-bundled"] }
fltk-evented = "0.1"
use fltk::{prelude::*, *};
use std::{cell::RefCell, rc::Rc, thread};
fn main() {
//create channel
let (mainSender, mainReceiver) = app::channel::<i32>();
//create application, window, button
let mainApp = app::App::default();
let mut win = window::Window::default().with_size(500, 500);
let mut btn = button::Button::new(20, 20, 100, 40, "START");
win.end();
win.show();
let mainSenderClone = mainSender.clone();
btn.handle(move |thisBtn, evt| match evt {
//btn event handler
enums::Event::Push => {
//click event
thread::spawn(move || {
//create thread
let mut cnt = 0; //10 iterations
while (cnt < 10) {
mainSenderClone.send(cnt);
//println!("sent_from_thread: {}",cnt); - uncommenting this fixes the situation
cnt += 1;
}
});
true //event handled
}
_ => false, //ignore other events
});
//start listening
while mainApp.wait() {
if let Some(msg) = mainReceiver.recv() {
println!("RECEIVED: {}", msg);
}
}
}
The output (without println!() in the thread):
RECEIVED: 1
RECEIVED: 3
RECEIVED: 5
RECEIVED: 7
RECEIVED: 9
With println!():
sent_from_thread: 0
RECEIVED: 0
sent_from_thread: 1
RECEIVED: 1
sent_from_thread: 2
RECEIVED: 2
sent_from_thread: 3
RECEIVED: 3
sent_from_thread: 4
RECEIVED: 4
sent_from_thread: 5
RECEIVED: 5
sent_from_thread: 6
RECEIVED: 6
sent_from_thread: 7
RECEIVED: 7
sent_from_thread: 8
RECEIVED: 8
sent_from_thread: 9
RECEIVED: 9

So, after few days of learning magic, I decided to do "cargo update + build" and then everything started working properly.
I still don't quite understand what was that and how did the previous downloaded dependencies get corrupted, but.. yeah, updating fixed it
Another question, I still dont get why sometimes the channel receives all the 10 messages immediately, and sometimes 0123 [1-2 seconds pause] 456789. But I think I will eventually find it out
Thanks to everyone who took my code and tested it, especially #denys-séguret, #joe-jingyu

Related

Why does an infinite loop block Worker output?

I wrote and ran the following script on a Linux system and expected a growing list of numbers, that stops after one second.
const { Worker, isMainThread } = require('node:worker_threads');
if (isMainThread) {
new Worker(__filename);
setTimeout(process.exit, 1000);
} else {
let i = 0;
while (true) {
console.error(i++);
}
}
However, the actual output is
0
I've read that a blocked parent thread can block the output of worker threads. I tried
const { Worker, isMainThread } = require('node:worker_threads');
if (isMainThread) {
new Worker(__filename);
setTimeout(process.exit, 1000);
} else {
let i = 0;
while (i < 10) {
console.error(i++);
}
}
instead and got
0
1
2
3
4
5
6
7
8
9
It seems like the infinite loop inside the worker thread blocks the output, but I can't find the reason.
I've read https://nodejs.org/api/worker_threads.html#new-workerfilename-options and can't find anything that describes the behavior. I would understand that an infinite loop in the parent thread could block the output, but not an infinite loop in the worker thread.
I wrote another script to check whether process.stderr or the parent thread are blocked, but
const { Worker, isMainThread, parentPort } = require('node:worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
worker.on('message', console.error);
setTimeout(() => {
process.exit();
}, 1000);
} else {
let i = 0;
while (true) {
parentPort.postMessage(i++);
}
}
produces the expected output:
0
1
2
3
.
.
.
139108
139109
139110
139111
139112
Why is the output blocked? In addition, if the infinite loop were blocking the output, why would I see the first output 0?
I found this note and I think it's relate to my question, but I don't fully understand, what it means:
https://nodejs.org/dist/latest-v18.x/docs/api/process.html#a-note-on-process-io
TTYs are synchronous on Linux and pipes and sockets are asynchrnous on Linux.

Too many connection from pinging in Rust?

I have a code to check a network connection like this
fn network_connection() {
loop {
let output = Command::new("ping")
.arg("-c")
.arg("1")
.arg("google.com")
.output()
.expect("[ ERR ] Failed to execute network check process");
let network_status = output.status;
if network_status.success() == false {
Command::new("init")
.arg("6");
}
thread::sleep(Duration::from_millis(60000));
}
}
fn main() {
thread::spawn(|| {
network_connection();
});
...
this should ping google every 60 seconds. But when I'm looking at number of request sent to router its like 200 requests per 10 minutes.
Is this spamming more threads than one?
main() is running only once.

Reading a line in a BufReader creates an infinite loop

I'm trying to receive a message (server side) on the network using TcpListener in Rust.
Here's the server code:
// Instanciate TcpListener
let server = TcpListener::bind("0.0.0.0:52001").expect("Could not bind");
match server.accept() { // Waiting new connection from a client
Ok((stream, addr)) => {
println!("New connection from {}", addr);
// Wrapping the stream in a BufReader
let mut reader = BufReader::new(&stream);
let mut message = String::new();
loop { // Entering the loop when a client is connected
reader.read_line(&mut message).expect("Cannot read new line");
println!("message received: {}", message);
message.clear();
}
}
Err(e) => {
println!("Fail: {:?}", e)
}
}
Here's my Kotlin client:
Socket("192.168.134.138", 52001).use { client ->
client.getOutputStream().use { out ->
out.write("test\n".toByteArray())
}
}
while(true) {
Thread.sleep(15_000)
}
The client send the following line: test\n and it ends with a linebreak for the server to read.
The intended behaviours would be that on the server side it prints message received: test and then the server waits at the read_line() instruction for the next line
It works because I receive the test but the read_line() method does not seem to block nor wait for another message. So it creates an infinite loop. So in the terminal I'm getting:
New connection from 192.168.134.123:7869
message received: test
message received:
message received:
message received:
message received:
Process finished with exit code 130 (interrupted by signal 2: SIGINT)
And I have to stop the program forcefully.
Any ideas?
To detect the end of the stream, you need to check if read_line() returned Ok(0):
From the docs:
If this function returns Ok(0), the stream has reached EOF.
loop { // Entering the loop when a client is connected
let mut message = String::new();
if reader.read_line(&mut message).expect("Cannot read new line") == 0 {
break;
}
println!("message received: {}", message);
}
Another way option is to use BufReader::lines() iterator:
for line in reader.lines() {
let message = line.expect("Cannot read new line");
println!("message received: {}", message);
}
This approach is a bit inefficient as it allocates a new String on every iteration. For best performance, you should allocate a single String and reuse it like #BlackBeans pointed out in a comment:
let mut message = String::new();
loop { // Entering the loop when a client is connected
message.clear();
if reader.read_line(&mut message).expect("Cannot read new line") == 0 {
break;
}
println!("message received: {}", message);
}

Modbus commands within node.js

I'm new here and try to build my webaplication with node.js to read and write modbus data from a door operator.
So far I have successfully used modbus-serial package to send and receive data with function code 3 and 16.
var ModbusRTU = require("modbus-serial");
var client = new ModbusRTU();
client.connectRTUBuffered("/dev/ttyUSB0", { baudRate : 9600, dataBits : 8, stopBits : 1, parity : "none", });
client.setID(2);
socket.on('op_mode', function (data, err) {
if (err){
console.log(err);
} else {
console.log('op_mode : ' + data);
client.writeRegisters(20, [data, 0]); //data is a number between 1 and 6
}
});
This represents the equivalent of typing "2 16 0 20 0 2 4 0 2 0 0" into Realterm on Windows.
With "2 3 0 20 0 2" I'm able to read data with Realterm. An the equivalent in node.js is:
client.readHoldingRegisters(20, 2, function(err, data) {
if (err){
console.log(err);
} else {
console.log('Reg 20: ' + data.data[0]);
}
});
Now I need to send the command "2 100 252 249 0 0" with node.js which I don't know how to do as the function code 100 is not present. The same command in Realterm is working fine.
For me it would also be ok to use the SerialPort package but need some help to get the code right to receive an answer from my operator.
Thanks in advance.
Additional information from 08.02.2021
Message information from documentation:
Slave address Byte 0 = 2
Function code Byte 1 = 100
Byte 2 = 252
Byte 3 = 249
Byte 4 = 0
Byte 5 = 0
Modbus16 CRC must be added. Response has the same structure.

What do I wait or join on when using channels and threads?

Here's an example but what should I wait on to decide when it is done. Do we have a better way to wait for the channel to be empty and all the threads to have completed? Full example is at http://github.com/posix4e/rust_webcrawl
loop {
let n_active_threads = running_threads.compare_and_swap(0, 0, Ordering::SeqCst);
match rx.try_recv() {
Ok(new_site) => {
let new_site_copy = new_site.clone();
let tx_copy = tx.clone();
counter += 1;
print!("{} ", counter);
if !found_urls.contains(&new_site) {
found_urls.insert(new_site);
running_threads.fetch_add(1, Ordering::SeqCst);
let my_running_threads = running_threads.clone();
pool.execute(move || {
for new_url in get_websites_helper(new_site_copy) {
if new_url.starts_with("http") {
tx_copy.send(new_url).unwrap();
}
}
my_running_threads.fetch_sub(1, Ordering::SeqCst);
});
}
}
Err(TryRecvError::Empty) if n_active_threads == 0 => break,
Err(TryRecvError::Empty) => {
writeln!(&mut std::io::stderr(),
"Channel is empty, but there are {} threads running",
n_active_threads);
thread::sleep_ms(10);
},
Err(TryRecvError::Disconnected) => unreachable!(),
}
}
This is actually a very complicated question, one with a great potential for race conditions! As I understand it, you:
Have an unbounded queue
Have a set of workers that operate on the queue items
The workers can put an unknown amount of items back into the queue
Want to know when everything is "done"
One obvious issue is that it may never be done. If every worker puts one item back into the queue, you've got an infinite loop.
That being said, I feel like the solution is to track
How many items are queued
How many items are in progress
When both of these values are zero, then you are done. Easier said than done...
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize,Ordering};
use std::sync::mpsc::{channel,TryRecvError};
use std::thread;
fn main() {
let running_threads = Arc::new(AtomicUsize::new(0));
let (tx, rx) = channel();
// We prime the channel with the first bit of work
tx.send(10).unwrap();
loop {
// In an attempt to avoid a race condition, we fetch the
// active thread count before checking the channel. Otherwise,
// we might read nothing from the channel, and *then* a thread
// finishes and added something to the queue.
let n_active_threads = running_threads.compare_and_swap(0, 0, Ordering::SeqCst);
match rx.try_recv() {
Ok(id) => {
// I lie a bit and increment the counter to start
// with. If we let the thread increment this, we might
// read from the channel before the thread ever has a
// chance to run!
running_threads.fetch_add(1, Ordering::SeqCst);
let my_tx = tx.clone();
let my_running_threads = running_threads.clone();
// You could use a threadpool, but I'm spawning
// threads to only rely on stdlib.
thread::spawn(move || {
println!("Working on {}", id);
// Simulate work
thread::sleep_ms(100);
if id != 0 {
my_tx.send(id - 1).unwrap();
// Send multiple sometimes
if id % 3 == 0 && id > 2 {
my_tx.send(id - 2).unwrap();
}
}
my_running_threads.fetch_sub(1, Ordering::SeqCst);
});
},
Err(TryRecvError::Empty) if n_active_threads == 0 => break,
Err(TryRecvError::Empty) => {
println!("Channel is empty, but there are {} threads running", n_active_threads);
// We sleep a bit here, to avoid quickly spinning
// through an empty channel while the worker threads
// work.
thread::sleep_ms(1);
},
Err(TryRecvError::Disconnected) => unreachable!(),
}
}
}
I make no guarantees that this implementation is perfect (I probably should guarantee that it's broken, because threading is hard). One big caveat is that I don't intimately know the meanings of all the variants of Ordering, so I chose the one that looked to give the strongest guarantees.

Resources