Comments (15)
Yep, that's equivalent to this minimal solution that I had in mind:
use std::sync::{Arc, Mutex};
use std::thread;
struct JobStatus {
jobs_completed: u32,
}
fn main() {
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
let status_shared = status.clone();
thread::spawn(move || {
for _ in 0..10 {
thread::sleep_ms(500);
status_shared.lock().unwrap().jobs_completed += 1;
}
});
while status.lock().unwrap().jobs_completed < 10 {
println!("waiting...");
thread::sleep_ms(1000);
}
}
from rustlings.
Anticipating a deadlock due to the while loop I opted to use a normal loop instead. The point being that I was unsure how the while loop would handle the lock, whether it would be released before the content of the loop was executed (though apparently it does so my approach was a bit more convoluted than necessary). (Also this way I could print the number of completed jobs.)
struct JobStatus {
jobs_completed: u32,
}
fn main() {
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
let status_shared = status.clone();
thread::spawn(move || {
for _ in 0..10 {
thread::sleep(Duration::from_millis(250));
let mut x = status_shared.lock().unwrap();
x.jobs_completed += 1;
}
});
loop {
{
let x = status.lock().unwrap();
println!("{} done", x.jobs_completed);
if x.jobs_completed >= 10 { break; }
} // Lock going out of scope
thread::sleep(Duration::from_millis(500));
}
}
from rustlings.
This syntax was called a weird hack but I think it's kind of cute here.
while {
let handle = status.lock().unwrap();
println!("{} done", handle.jobs_completed);
handle.jobs_completed < 10
} {
println!("waiting... ");
thread::sleep(Duration::from_millis(500));
}
from rustlings.
neither of the above did work for me — I was always deadlocking.
what did work is this:
fn main() {
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
let status_shared = status.clone();
thread::spawn(move || {
for _ in 0..10 {
thread::sleep(Duration::from_millis(250));
status_shared.lock().unwrap().jobs_completed += 1;
}
});
fn jobs_completed(s: &Arc<Mutex<JobStatus>>) -> u32 {
s.lock().unwrap().jobs_completed
};
while jobs_completed(&status) < 10 {
println!("waiting... ");
thread::sleep(Duration::from_millis(500));
}
}
So I had to put the main thread's lock into a function.
from rustlings.
Any ideas why this only prints waiting...
once?
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
struct JobStatus {
jobs_completed: u32,
}
fn main() {
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
let status_shared = Arc::clone(&status);
thread::spawn(move || {
for _ in 0..10 {
let mut stat = status_shared.lock().unwrap();
stat.jobs_completed += 1;
println!("set completed jobs to {}", stat.jobs_completed);
thread::sleep(Duration::from_millis(250));
}
});
while status.lock().unwrap().jobs_completed < 10 {
println!("waiting... ");
thread::sleep(Duration::from_millis(500));
}
}
Output:
waiting...
set completed jobs to 1
set completed jobs to 2
set completed jobs to 3
set completed jobs to 4
set completed jobs to 5
set completed jobs to 6
set completed jobs to 7
set completed jobs to 8
set completed jobs to 9
set completed jobs to 10
EDIT: Just figured it out! Moving the thread::sleep()
to the end of the spawned thread will cause the spawned thread to always hold the lock on the mutex and never yield it back to the main thread, so the while
loop will only run once!
from rustlings.
@cyyyu That is a valid program, but by using join() to block until the thread has finished running it avoids the main problem of the exercise, which is to experiment with sharing memory between two threads that are actively running simultaneously.
from rustlings.
AtomicU32 is a fine solution.
from rustlings.
Ok, so, real talk, your exercises are not straightforward for me, I am a Ruby developer who has not spawned threads in many moons :) So before I write hints for this, I want to check that I got a solution along the lines of what you were thinking for this one:
This was really great for me actually, because it put me more in the shoes of people who are newer to Rust than I am doing the exercises I wrote, which will help me write better hints, and I learned a lot working on this, which validates my hope that these are useful to people :)
// Make this compile!
use std::sync::{Arc, Mutex};
use std::thread;
struct JobStatus {
jobs_completed: u32,
}
fn main() {
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
let status_shared = status.clone();
thread::spawn(move || {
for _ in 0..10 {
thread::sleep_ms(250);
let mut status_shared = status_shared.lock().unwrap();
status_shared.jobs_completed += 1;
}
});
let status_check = status.clone();
let mut jobs_completed = {
let s = status_check.lock().unwrap();
s.jobs_completed
};
while jobs_completed < 10 {
println!("waiting... {}", jobs_completed);
thread::sleep_ms(500);
jobs_completed = {
let s = status_check.lock().unwrap();
s.jobs_completed
};
}
}
from rustlings.
I bumped the timeouts down because otherwise you hit the playground timeout limits :)
from rustlings.
The first hint gives a reference to a redirect page. In the 2nd version of the book, it starts talking about channels before shared state so I solved it using channels as:
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
for _ in 0..10 {
thread::sleep(Duration::from_millis(250));
tx.send(1).unwrap();
}
});
let mut received = 0;
while received < 10 {
received += rx.try_iter().sum::<i32>();
println!("waiting... ");
thread::sleep(Duration::from_millis(500));
}
}
... which is obviously not straight forward given the initial setup. But a nice little exercise!
from rustlings.
I got a solution similar to @jdm's solution except that status_shared
was put into a variable.
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
struct JobStatus {
jobs_completed: u32,
}
fn main() {
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
let status_shared = status.clone();
thread::spawn(move || {
for _ in 0..10 {
thread::sleep(Duration::from_millis(250));
let mut status_shared = status_shared.lock().unwrap();
status_shared.jobs_completed += 1;
}
});
while status.lock().unwrap().jobs_completed < 10 {
println!("waiting... ");
thread::sleep(Duration::from_millis(500));
}
}
from rustlings.
This worked for me:
use std::sync::{Mutex, Arc};
use std::thread;
use std::time::Duration;
struct JobStatus {
jobs_completed: Mutex<i32>,
}
fn main() {
let status = Arc::new(JobStatus { jobs_completed: Mutex::new(0) });
let status_shared = status.clone();
thread::spawn(move || {
for _ in 0..10 {
thread::sleep(Duration::from_millis(250));
let mut job_c = status_shared.jobs_completed.lock().unwrap();
*job_c += 1;
}
});
while *status.jobs_completed.lock().unwrap() < 10 {
println!("waiting... ");
thread::sleep(Duration::from_millis(500));
}
}
from rustlings.
what I just learned from The Rust Programming Language is that you can actually make it even simpler:
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
struct JobStatus {
jobs_completed: u32,
}
fn main() {
let status = Arc::new(Mutex::new(JobStatus { jobs_completed: 0 }));
let status_shared = Arc::clone(&status);
let handle = thread::spawn(move || {
for _ in 0..10 {
thread::sleep(Duration::from_millis(250));
let mut jobstatus = status_shared.lock().unwrap();
jobstatus.jobs_completed += 1;
}
});
handle.join().unwrap();
println!("Jobs completed: {}", status.lock().unwrap().jobs_completed);
}
does my program make sense?
from rustlings.
@jdm I forgot the purpose 😅thanks for explanation.
from rustlings.
Is there any reason i shouldn't use AtomicU32 for this purpose?
According to this performance comparison i found it should also be faster than by using Mutex.
Of course you need to specify the byte ordering which may introduce confusion for beginners.
This is my (working) program:
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::sync::atomic::{AtomicU32, Ordering};
struct JobStatus {
jobs_completed: AtomicU32,
}
fn main() {
let status = Arc::new(JobStatus { jobs_completed: AtomicU32::new(0) });
let status_clone = Arc::clone(&status);
thread::spawn(move || {
for _ in 0..10 {
thread::sleep(Duration::from_millis(250));
status_clone.jobs_completed.fetch_add(1, Ordering::Relaxed);
}
});
while status.jobs_completed.load(Ordering::Relaxed) < 10 {
println!("waiting... ");
thread::sleep(Duration::from_millis(500));
}
}
from rustlings.
Related Issues (20)
- Fixed the constant variable on 01_variables/variables6.rs
- Add Rustlings fast-track HOT 1
- Tests for errors3.rs
- Traduction en Français de rustlings HOT 3
- Idea - Migrate help issues to discussions in github HOT 1
- rustlings watch hangs HOT 2
- Maybe I'm the dummy -hashmaps3 HOT 2
- The last line of 'rustlings verify' does not display
- enums3 has an argument in the testing that does not compile HOT 3
- Use `git2` HOT 1
- Self-contained installation HOT 5
- Ratatui HOT 1
- variables3.rs -> println seems to ignore datatype if variable is given a value as parameter. HOT 2
- Use `Cargo.toml` instead of `rust-project.json` HOT 6
- Support third-party exercises
- Swap `strings` and `modules` sections
- Add a optional arg to specify the start exercise in watch mode HOT 1
- Devcontainer image might be outdated HOT 2
- Improved `move_semantics4` exercise proposal
- Bad hint at exercises/functions/functions4.rs
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rustlings.