1

I have a program that throws in another thread as follows:

#include <iostream>
#include <stdexcept>
#include <thread>

void op()
{
    std::cout << "OP HELLO WORLD" << std::endl;
    throw(std::runtime_error("OP ERROR"));
};

int main(int argc, char* argv[])
{
    //throw(std::runtime_error("MAIN ERROR"));
    std::thread t(op);
    t.join();
    std::cout << "MAIN HELLO WORLD" << std::endl;
};

I want my program to print a clear error message and stop. I know I can use std::abort or std::terminate, however the error message is not clear and does not contain the log "OP ERROR".

Could you please help me code a program that when fails exits and logs a clear error message. std::future does not work too when I tried a try, catch block?

Vero
  • 313
  • 2
  • 9
  • Catch the exception and display the message. Letting an exception escape from a thread results in a call to `std::terminate`. There is no required output when `std::terminate` is called. – Pete Becker Jan 14 '23 at 22:29
  • the goal is I want to know what the error is and the line and the file – Vero Jan 14 '23 at 22:29
  • In this case include this information in error message. You can create macro to simplify this. – sklott Jan 14 '23 at 22:34
  • Added version without `std::future` in my answer. – sklott Jan 14 '23 at 23:04

2 Answers2

2

Are you looking for something like this?

#include <iostream>
#include <stdexcept>
#include <thread>
#include <future>

void op()
{
    std::cout << "OP HELLO WORLD" << std::endl;
    throw(std::runtime_error("OP ERROR. File: " __FILE__ ", Line: "+ std::to_string(__LINE__)));
};

int main(int argc, char* argv[])
{
    //throw(std::runtime_error("MAIN ERROR"));
    auto res = std::async(op);
    try {
        res.get();
    } catch(const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
        return -1;
    }
    std::cout << "MAIN HELLO WORLD" << std::endl;
}

If you want to output errors for all threads without returning exceptions to main thread, you can setup your own version of terminate().

#include <iostream>
#include <cstdlib>
#include <exception>
#include <thread>

void op()
{
    std::cout << "OP HELLO WORLD" << std::endl;
    throw(std::runtime_error("OP ERROR"));
}

void my_terminate()
{
    auto eptr = std::current_exception();
    try {
        if (eptr) {
            std::rethrow_exception(eptr);
        }
    } catch(const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
    std::abort();
}

int main(int argc, char* argv[])
{
    std::set_terminate(my_terminate);
    //throw(std::runtime_error("MAIN ERROR"));
    std::thread t(op);
    t.join();
    std::cout << "MAIN HELLO WORLD" << std::endl;
}

For some reason MSVC uses per-thread handlers, and for it to work you need to call set_termnate() in every thread separatelly.

sklott
  • 2,634
  • 6
  • 17
  • Thanks very much. I am looking for something that throws inside the worked thread not outside :) Thanks so much again. But I think from the question, this is the answer. I should have specified throwing in the worker thread and stopping the programme from the worker thread. – Vero Jan 14 '23 at 22:36
1

To avoid the call to std::terminate, make sure exceptions don't "leak" outside the thread function.

void op()
{
    try {
        std::cout << "OP HELLO WORLD" << std::endl;
        throw std::runtime_error("OP ERROR");
    } catch (const std::exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
        exit(1);
    }
}

If you want to automatically see the exception's file and line number, in C++ it is not generally possible.

If you want to catch all exceptions in a single place in the main thread, you need to catch them and pass them to the main thread. There's a useful wrapper utility std::packaged_task which gives back a future on which you can wait for the result or an exception.

#include <iostream>
#include <stdexcept>
#include <thread>
#include <future>

void op()
{
    std::cout << "OP HELLO WORLD" << std::endl;
    throw std::runtime_error("OP ERROR");
}

int main(int argc, char* argv[])
{
    try {
        std::packaged_task<void()> task{&op};
        auto result = task.get_future();
        std::thread t{std::move(task)};
        t.join();
        result.get();
        std::cout << "MAIN HELLO WORLD" << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
    }
}
rustyx
  • 80,671
  • 25
  • 200
  • 267