2

I am new to threading, and I face the situation that confuses me ,I try to throw exception inside the function that I put in thread and at main() function I have a try and catch block,However I still get these error :

1. terminate called after throwing an instance of 'char const*'

2. terminate called recursively

Below is my code

mutex m;

void AccumulateRange(uint64_t &sum, uint64_t start, uint64_t end) {
    for (uint64_t i = start;i<end;++i){
        sum+=i;
        if (sum>10) 
            throw "Number Exceed";
    }
}

int main(){

    const uint64_t num_threads = 1000;
    uint64_t nums = 1000*1000*1000;
    vector<uint64_t> v(num_threads);
    vector<thread> threads;
    uint64_t steps = nums/num_threads;

    for (uint64_t i = 0;i<num_threads;++i){
        try{
            threads.push_back(thread(AccumulateRange,ref(v[i]),steps*i,(i+1)*steps));
        }
        catch (const char& exception){
            cout<<exception<<endl;
        }
    }
    for (auto &t : threads){
        if (t.joinable())
           t.join();    
    }
    uint64_t total = accumulate(begin(v),end(v),0);
    return 0;
}

Thanks in advance !

Pro_gram_mer
  • 749
  • 3
  • 7
  • 20
  • 1
    Your try catch might catch when an exception thrown while thread create, but not when a thread is executing. – Louis Go Jul 21 '20 at 09:01
  • 3
    Do not throw anything that is not `std::exception` – pptaszni Jul 21 '20 at 09:08
  • @LouisGo What do you mean by "try catch might catch when an exception thrown while thread create" ,How does this happen ? – Pro_gram_mer Jul 22 '20 at 00:55
  • @pptaszni Can you give me more detail or ref about what you said? I would like to learn more. – Pro_gram_mer Jul 22 '20 at 00:56
  • 1
    @Delta has explain it. You try catch could only catch the exception in creation thread, that is `std::system_error` while thread could not start. [reference](https://en.cppreference.com/w/cpp/thread/thread/thread). Once thread is created, exception in the thread must be catch in the thread because a thread has its own stack. Or use pptaszni's suggestion. – Louis Go Jul 22 '20 at 01:07
  • @LouisGo yeah, Thanks! I think i was wrong as I response below ,I thought main() would catch exception thrown from thread ,However,from your ref ,it says "Any return value from the function is ignored. If the function throws an exception, std::terminate is called. In order to pass return values or exceptions back to the calling thread, std::promise or std::async may be used." – Pro_gram_mer Jul 22 '20 at 01:24
  • Because it is a common practice to `try { something(); } catch (const std::exception& e) {}`, which will not work if you throw some arbitrary type. [Here](https://stackoverflow.com/a/53630081/4165552) some discussion about "then why is it allowed to throw anything". – pptaszni Jul 22 '20 at 06:12

2 Answers2

5

To elaborate a bit on @DeltA answer: Instead of working with std::thread and passing the exceptions with pointers, you can use std::future because it stores the thrown exceptions in its shared state:

void AccumulateRange(uint64_t& sum, uint64_t start, uint64_t end)
{
    for (uint64_t i = start; i < end; ++i)
    {
        sum += i;
        if (sum > 10)
            throw std::runtime_error("Number Exceed");
    }
}

int main()
{
    const uint64_t num_threads = 1000;
    uint64_t nums = 1000 * 1000 * 1000;
    std::vector<uint64_t> v(num_threads);
    std::vector<std::future<void>> futures;
    uint64_t steps = nums / num_threads;
    for (uint64_t i = 0; i < num_threads; ++i)
    {
        futures.push_back(std::async(std::launch::async, AccumulateRange, std::ref(v[i]), steps * i, (i + 1) * steps));
    }
    for (auto& f : futures)
    {
        try
        {
            f.get();
        }
        catch (const std::exception& e)
        {
            std::cout << e.what() << std::endl;
        }
    }
}
pptaszni
  • 5,591
  • 5
  • 27
  • 43
  • Thanks! I would look into it,but before that,I would like to know why join() is not needed any more? – Pro_gram_mer Jul 22 '20 at 01:22
  • 1
    Because `std::future` doesn't have `join`. Instead it has `get` that behaves in the similar way. [future](https://en.cppreference.com/w/cpp/thread/future), [async](https://en.cppreference.com/w/cpp/thread/async). – pptaszni Jul 22 '20 at 06:20
3

You can't catch exceptions between threads. When an exception is thrown, the call stack gets unwound, looking for a catch. Each thread has it's own stack. An alternative could be to use some kind of global variable or queue or other mechanism to pass exceptions from the worker threads to the main thread. Check this Catching exception from worker thread in the main thread

DeltA
  • 564
  • 4
  • 12