How to return an error to the upper from inside a Thread

Basically what I want is to return the error to the upper function, from inside the thread. How can I do it?

Thread::spawn returns a JoinHandle that can be used to get the return value of the thread's closure. The calling thread calls join. This is how to return a value when the thread ends.

If you want to return multiple values while continuing to execute the thread, use a channel as in the second example here.

5 Likes

As the thread doesn't end I will probably use a channel. Would you say that's a bad practice? This code seems weird to me. tysm.

Not at all, it's very common and efficient.

I see, ty. Just another question... The code below is slightly modified from the above.

fn handle_events(self) -> Arc<Mutex<Quit>> {
        let quit: Arc<Mutex<Quit>> = Arc::new(Mutex::new(self));

        {
            let quit = Arc::clone(&quit);
            std::thread::spawn(move || -> io::Result<()> {
                loop {
                    match event::read()? {
                        Event::Key(key_event) if key_event.kind == KeyEventKind::Press => {
                            match key_event.code {
                                // MATCH THE INPUT WITH ITS ACTION.
                                KeyCode::Char('q') => {
                                    quit.lock().unwrap().bool = true;
                                }
                                _ => {}
                            }
                        }
                        _ => {}
                    };
                }
            });
        }

        return quit;
    }

what exactly would happen if "event::read() returned an error for the "?"? Would the loop or thread stop? I wonder if that's a better option than the first idea of matching the result.

Question mark returns from the current function, in this case - from the closure passed to thread::spawn. When this closure returns, thread stops, and the return value can be retrieved from the JoinHandle returned by spawn.

2 Likes

I get it. As I want it running the whole time I don't think it's interesting to keep the ?. Will prob go to the old way. Thank you all, I'm closing

Wish I could mark two answers as the solution tho.

Reopened it because I think that's not the way.

Only a single error should be enough to stop the whole program, so I see using a channel a very very inneficient way of doing it in this specific case.

But the function already returns "quit" right after the thread is called, it doesn't matter what's the return value of the closure.

As handle_events is only called once, is it possible to:

Even after calling the function and returning "quit", make the program panic whenever the closure returns an Err, without a channel or similar?

You have a loop in the thread, so it doesn't stop right when it is "called" (if by that you mean "started"), in the code you've shown. In that code it stops when event::read returns an error. If you're using a channel to send the error, the reader of that channel (calling recv in the other thread) will also return an error, because the channel will be closed by the sending thread when it exits (all variables are dropped including the channel).

This is an unexpected error, so you could cause either or both threads to panic when the channel returns an error, if you really want that. You can do that by call Result::unwrap or Result::expect instead of using the trailing ? to return the error from the thread. You can do this in the calls to both send and recv.

You can do that by calling panic! when you see the quit key in the thread checking for the key, after setting the quit boolean, and by also calling panic when you notice the quit boolean is set in the other thread. If you also panic when there is a send or recv error, then you don't need a channel.

But I don't recommend panic when there is a normal shutdown, because this will print the backtrace and the error, and the process will exit with an error. With a normal shutdown, usually an error should not be printed and you may also (eventually) need to do some cleanup before exiting.

1 Like

I don't want to use channels as I think it's too robust for its purpose in this code. Panic is not a good option, I see, but will it work if I return an Err(anyhow!("..."))?

By work I mean, return the err from the closure and then send it to the function caller, even after quit has already returned and been used

asking that cuz I can't test it now

You have to join the thread with the JoinHandle (which will wait for the thread to stop -- e.g. by having returned the Err(anyhow!(...))). If you want to join it after quit is returned, you also need to return the JoinHandle somehow, so the caller can do the joining.

1 Like

Yes, you can return from the thread's closure after setting the quit flag. There is nothing stopping you.

What you do with the return value of the closure depends on what you're doing with the JoinHandle. You haven't shown that code.

1 Like

I used to think that after quit being returned that ""entry"" would close and nothing else could be done in it. Just a misconception that I don't know where came from haha. Thank you, will try it asap.

1 Like