Rust Concurrent Task Scheduler with Threads
Rust Threads and Synchronization: Exercise-6 with Solution
Write a Rust program that develops a concurrent task schedule that executes tasks using multiple threads.
Sample Solution:
Rust Code:
use std::sync::{Arc, Mutex};
use std::thread;
// Define a type for tasks
type Task = Box<dyn FnOnce() + Send + 'static>;
// Define a structure for the task scheduler
struct TaskScheduler {
tasks: Arc<Mutex<Vec<Task>>>,
threads: Vec<thread::JoinHandle<()>>,
}
impl TaskScheduler {
// Create a new instance of the task scheduler
fn new() -> Self {
TaskScheduler {
tasks: Arc::new(Mutex::new(Vec::new())),
threads: Vec::new(),
}
}
// Add a task to the scheduler
fn add_task(&self, task: Task) {
self.tasks.lock().unwrap().push(task);
}
// Start the task scheduler with a specified number of threads
fn start(&mut self, num_threads: usize) {
for _ in 0..num_threads {
let tasks = Arc::clone(&self.tasks);
let handle = thread::spawn(move || {
loop {
// Lock the tasks vector
let task = tasks.lock().unwrap().pop();
// Execute the task if it exists
if let Some(task) = task {
task();
} else {
// If no task is available, break the loop
break;
}
}
});
self.threads.push(handle);
}
}
// Wait for all threads to finish executing
fn wait_all(&mut self) {
for handle in self.threads.drain(..) {
handle.join().unwrap();
}
}
}
fn main() {
// Create a new task scheduler
let mut scheduler = TaskScheduler::new();
// Add tasks to the scheduler
for i in 0..10 {
let task = Box::new(move || {
println!("Task {} executed by thread {:?}", i, thread::current().id());
});
scheduler.add_task(task);
}
// Start the task scheduler with 4 threads
scheduler.start(4);
// Wait for all threads to finish executing
scheduler.wait_all();
}
Output:
Task 9 executed by thread ThreadId(2) Task 8 executed by thread ThreadId(5) Task 5 executed by thread ThreadId(5) Task 4 executed by thread ThreadId(5) Task 3 executed by thread ThreadId(5) Task 2 executed by thread ThreadId(5) Task 1 executed by thread ThreadId(5) Task 0 executed by thread ThreadId(5) Task 7 executed by thread ThreadId(4) Task 6 executed by thread ThreadId(3)
Explanation:
In the exercise above,
- Define a Task type alias, representing a closure that takes no arguments and returns nothing (FnOnce() + Send + 'static). This type can be executed in parallel and sent between threads.
- Define a "TaskScheduler" structure to manage the execution of tasks. It contains a vector of tasks wrapped in a mutex to allow multiple threads to access it safely, as well as a vector of thread handles to keep track of spawned threads.
- The "TaskScheduler" has methods to add tasks (add_task), start executing tasks with a specified number of threads (start), and wait for all threads to finish executing (wait_all).
- In the "main()" function, we create a new "TaskScheduler" instance and add some tasks to it.
- We start the task scheduler with 4 threads using the "start()" method.
- Finally, we wait for all threads to finish executing using the "wait_all()" method
Rust Code Editor:
Previous: Rust Concurrent Web Server with Threads.
Next: Rust Parallel Merge Sort Algorithm with Threads.
What is the difficulty level of this exercise?
Test your Programming skills with w3resource's quiz.
It will be nice if you may share this link in any developer community or anywhere else, from where other developers may find this content. Thanks.
https://www.w3resource.com/rust/threads_and_synchronization/rust-threads-and-synchronization-exercise-6.php
- Weekly Trends and Language Statistics
- Weekly Trends and Language Statistics