Threads and handle.join with file module

My test code is working:

main.rs


use chrono::prelude::*;
use std::thread;

fn main() {
    // - - - - - - - - - - - - - - - - - - - -
    let handle_01 = thread::spawn(move || {
         // ... 
    });
    // - - - - - - - - - - - - - - - - - - - -
    let handle_02 = thread::spawn(move || {
         // ... 
    });
    // - - - - - - - - - - - - - - - - - - - -
    
    let t1: DateTime<Local> = Local::now();
    let mut a: u64 = 0; 
    for i in 0..1000000 {
        a = i + 1;
    }
    println!("a = {:}", a);
    let t2: DateTime<Local> = Local::now();                                                     
    println!("{:}", t2 - t1);
    //
    handle_01.join().unwrap();
    handle_02.join().unwrap();
}

I want to split code into file modules: main.rs with tds01.rs and tds02.rs.

main.rs

use chrono::prelude::*;
mod threads;

fn main() {
    // - - - - - - - - - - - - - - - - - - - -
    threads::tds01::tds_01();    
    // - - - - - - - - - - - - - - - - - - - -
    threads::tds02::tds_02();
    // - - - - - - - - - - - - - - - - - - - -

    let t1: DateTime<Local> = Local::now();
    let mut a: u64 = 0; 
    for i in 0..1000000 {
        a = i + 1;
    }
    println!("a = {:}", a);
    let t2: DateTime<Local> = Local::now();                                                     
    println!("{:}", t2 - t1);
    // *block handle*
    // handle_01.join().unwrap(); // threads::tds01::tds_01().handle_01.join().unwrap();
    // handle_02.join().unwrap(); // threads::tds02::tds_02().handle_02.join().unwrap();
    //                               ^_ error[E0609]: no field `handle_01` on type `()`
}

tds01.rs

use chrono::prelude::*;
use std::thread;

pub fn tds_01() {
       let handle_01 = thread::spawn(move || {
            // ...
       });
}

tds02.rs

use chrono::prelude::*;
use std::thread;

pub fn tds_02() {
       let handle_02 = thread::spawn(move || {
            // ...
       });
}

How write correctly *block handle* in last main.rs?
If number of threads increase my code give them a chance to end before the main?

The basic problem in your code is that tds_01() and tds_02() do not return a value, so the return type is actually () rather than JoinHandle, which is what the error message in the comment is trying to tell you. You want to return the JoinHandle from tds_01() and tds_02():

tds_01.rs

use chrono::prelude::*;
use std::thread;

pub fn tds_01() -> JoinHandle {
       thread::spawn(move || {
            // ...
       })
}

tds_02.rs

use chrono::prelude::*;
use std::thread;

pub fn tds_02() -> JoinHandle {
       thread::spawn(move || {
            // ...
       })
}

Note that I've avoided storing the handles in a let binding in these functions and just returned the JoinHandles directly, since you don't seem to be doing anything else with it there. You'll want to store the returned handle in main() and call join() on that.

3 Likes

Thanks.
Gives an error after correction:

error[E0412]: cannot find type `JoinHandle` in this scope
  --> src\threads\tds01.rs:12:20
   |
12 | pub fn tds_01() -> JoinHandle {
   |                    ^^^^^^^^^^ not found in this scope
   |
help: consider importing one of these items
   |
1  | use crate::threads::tds01::thread::JoinHandle;
   |
1  | use std::thread::JoinHandle;

if use std::thread::JoinHandle; then

error[E0107]: missing generics for struct `JoinHandle`
  --> src\threads\tds01.rs:12:20
   |
12 | pub fn tds_01() -> JoinHandle {
   |                    ^^^^^^^^^^ expected 1 generic argument
   |
help: add missing generic argument
   |
12 | pub fn tds_01() -> JoinHandle<T> {
   |                              +++

if ... then did not work out:

12 | pub fn tds_01() -> JoinHandle<T> {
   |                               ^ not found in this scope
   |
help: you might be missing a type parameter
   |
12 | pub fn tds_01<T>() -> JoinHandle<T> {
   |              +++

Ah, sorry, forgot the import and the fact that JoinHandle has a type parameter.

The T parameter to JoinHandle should be the type output from the closure passed to spawn(). I can't properly tell you what that is without seeing the body of the closures, but if it doesn't specifically return a value then you want JoinHandle<()>.

If set JoinHandle<()>

pub fn tds_01() -> JoinHandle<()> {
    thread::spawn(move || {
    let t5: DateTime<Local> = Local::now();
    let mut c: u64 = 0; 
    for j in 0..1000000000 {
        c = j + 1;
    }    
    println!("c = {:}", c);
    let mut d: u64 = 1_000_000_009; 
    for _j in 0..1000000000 {
        d = d - 1;
    }
    let t6: DateTime<Local> = Local::now();
    println!("d = {:}", d);
    println!("d_65 = {:}", t6 - t5);
    });
}

get:

error[E0308]: mismatched types
  --> src\threads\tds01.rs:12:20
   |
12 | pub fn tds_01() -> JoinHandle<()> { // JoinHandle<()>
   |        ------      ^^^^^^^^^^^^^^ expected `JoinHandle<()>`, found `()`
   |        |
   |        implicitly returns `()` as its body has no tail or `return` expression
...
27 | });
   |   - help: remove this semicolon to return this value
   |
   = note: expected struct `JoinHandle<()>`
           found unit type `()`

For more information about this error, try `rustc --explain E0308`.

if set

pub fn tds_01() -> () {
    thread::spawn(move || {
    // ...
}

code works,
but how to create the string correctly in main.rs:

threads::tds01::tds_01().thread.join().unwrap();
threads::tds02::tds_02().thread.join().unwrap();
don't work

You have a semicolon after the spawn() call in your code, that discards the return value (making the return type ()). Note that there wasn't a semicolon in my reply earlier. Leaving it out ensures the JoinHandle is returned.

You can then just call join() on the values returned from tds_01() and tds_02().

file tds01.rs corrected,
also tds02.rs:

pub fn tds_02() -> JoinHandle<()> {
    thread::spawn(move || {    
    let t7: DateTime<Local> = Local::now();
    let mut e: u64 = 0; 
    for k in 0..1000000000 {
        e = k + 1;
    }    
    println!("e = {:}", e);
    let mut f: u64 = 1_000_000_009; 
    for _h in 0..1000000000 {
        f = f - 1;
    }
    let t8: DateTime<Local> = Local::now();
    println!("f = {:}", f);
    println!("d_87 = {:}", t8 - t7);
    })
}

main.rs

// ...
   threads::tds01::tds_01().join();
   threads::tds02::tds_02().join();
}

main.rs runs but goes through some threads twice
and for a long time, for example:

c = 1000000000
e = 1000000000
a = 1000000000
d_21 = PT10.947384200S
d = 9
d_65 = PT20.423553300S
b = 8
d_43 = PT10.074562400S
f = 9
d_87 = PT21.110611100S
c = 1000000000
d = 9
d_65 = PT19.486577800S
e = 1000000000
f = 9
d_87 = PT19.617245S

That does look like the threads are being run twice. Are you calling the tds_01() and tds_02() functions twice?

main.rs

use chrono::prelude::*;
mod p0010_threads;

fn main() {
    println!("[ - - - - - - - - - - - - - - - - - - -\n");

    // - - - - - - - - - - - - - - - - -
    p0010_threads::tds01::tds_01();
    p0010_threads::tds02::tds_02();
    //          ...     ::tds_03();
    // - - - - - - - - - - - - - - - - -

    //      * main_thread *:
    let t1: DateTime<Local> = Local::now();
    let mut a: u64 = 0; 
    for i in 0..1000000000 {
        a = i + 1;
    }
    println!("a = {:}", a);
    let t2: DateTime<Local> = Local::now();                                                     
    println!("d_21 = {:}", t2 - t1);
    //
    let t3: DateTime<Local> = Local::now();
    let mut b: u64 = 1_000_000_008; 
    for _i in 0..1000000000 {
        b = b - 1;
    }
    println!("b = {:}", b);
    let t4: DateTime<Local> = Local::now();
    println!("d_43 = {:}", t4 - t3);

    // -   * handle_01 & handle_02 *:
    // p0010_threads::tds01::tds_01().join().unwrap();
    // p0010_threads::tds02::tds_02().join().unwrap();
       p0010_threads::tds01::tds_01().join();
       p0010_threads::tds02::tds_02().join();
    println!("\n- - - - - - - - - - - - - - - - - - - ]");
}

mod.rs

pub mod tds01;
pub mod tds02;
// ...

tds01.rs

use chrono::prelude::*;
use std::thread;
use std::thread::JoinHandle;

pub fn tds_01() -> JoinHandle<()> {
    thread::spawn(move || {
    let t5: DateTime<Local> = Local::now();
    let mut c: u64 = 0; 
    for j in 0..1000000000 {
        c = j + 1;
    }    
    println!("c = {:}", c);
    let mut d: u64 = 1_000_000_009; 
    for _j in 0..1000000000 {
        d = d - 1;
    }
    let t6: DateTime<Local> = Local::now();
    println!("d = {:}", d);
    println!("d_65 = {:}", t6 - t5);
})// `;`
//
}

tds02.rs

use chrono::prelude::*;
use std::thread;
use std::thread::JoinHandle;

pub fn tds_02() -> JoinHandle<()> {
    thread::spawn(move || {    
    let t7: DateTime<Local> = Local::now();
    let mut e: u64 = 0; 
    for k in 0..1000000000 {
        e = k + 1;
    }    
    println!("e = {:}", e);
    let mut f: u64 = 1_000_000_009; 
    for _h in 0..1000000000 {
        f = f - 1;
    }
    let t8: DateTime<Local> = Local::now();
    println!("f = {:}", f);
    println!("d_87 = {:}", t8 - t7);
})// `;`
//
}

cargo run

warning: unused `Result` that must be used
  --> src\main.rs:46:5
   |
46 |     p0010_threads::tds01::tds_01().join();
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: this `Result` may be an `Err` variant, which should be handled
   = note: `#[warn(unused_must_use)]` on by default

...


[ - - - - - - - - - - - - - - - - - - -
a = 1000000000
d_21 = PT10.038369800S
e = 1000000000
c = 1000000000
b = 8
d_43 = PT9.415238600S
f = 9
d_87 = PT19.519394500S
d = 9
d_65 = PT19.522368500S
c = 1000000000
d = 9
d_65 = PT19.375126S
e = 1000000000
f = 9
d_87 = PT19.187284600S
- - - - - - - - - - - - - - - - - - - ]

else 
... > cargo run

[ - - - - - - - - - - - - - - - - - - -
a = 1000000000
d_21 = PT10.010982700S
e = 1000000000
c = 1000000000
b = 8
d_43 = PT9.488970100S
f = 9
d_87 = PT19.559540400S
d = 9
d_65 = PT19.591165400S
c = 1000000000
d = 9
d_65 = PT18.915709400S
e = 1000000000
f = 9
d_87 = PT18.982899700S
- - - - - - - - - - - - - - - - - - - ]

I want to get the total execution time main.rs ~ 20 sec.
get an error about handled
so asked how to write correctly.
Thanks.

In main() you want to store the JoinHandles to join them later. By calling tds_01() and tds_02() a second time you are creating a second pair of threads and joining those threads rather than the original. So main should look like this:

use chrono::prelude::*;
mod p0010_threads;

fn main() {
    println!("[ - - - - - - - - - - - - - - - - - - -\n");

    // - - - - - - - - - - - - - - - - -
    let handle01 = p0010_threads::tds01::tds_01();
    let handle02 = p0010_threads::tds02::tds_02();
    //          ...     ::tds_03();
    // - - - - - - - - - - - - - - - - -

    //      * main_thread *:
    let t1: DateTime<Local> = Local::now();
    let mut a: u64 = 0; 
    for i in 0..1000000000 {
        a = i + 1;
    }
    println!("a = {:}", a);
    let t2: DateTime<Local> = Local::now();                                                     
    println!("d_21 = {:}", t2 - t1);
    //
    let t3: DateTime<Local> = Local::now();
    let mut b: u64 = 1_000_000_008; 
    for _i in 0..1000000000 {
        b = b - 1;
    }
    println!("b = {:}", b);
    let t4: DateTime<Local> = Local::now();
    println!("d_43 = {:}", t4 - t3);

    // -   * handle_01 & handle_02 *:
    handle01.join().unwrap();
    handle02.join().unwrap();
    println!("\n- - - - - - - - - - - - - - - - - - - ]");
}

(playground with the modules)

Note the let bindings storing handle01 and handle02 to be joined at the end.

4 Likes

Works. Thank you very much.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.