Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Segmentation fault using array of promises

I've written multithreading program, using promises and futures to check whether given number is prime. The correctness or efficiency of this program is not a point, but fact of the segmentation error which occurs in every execution - I had similar problem with more complex program, so I've written this simple one to understand it, and the error is still here. Maybe I don't understand something about concurrency, or promises/futures, but I think that everything is done here in proper way... Can anybody explain why it's not working? It would be very helpful :)

Here's the code:

#include <future>
#include <thread>
#include <iostream>
#include <initializer_list>
#include <vector>
#include <cassert>


namespace {
const int THREADS_NUMBER = 8;

void f(int n, std::vector<int>& divisiors, std::promise<bool>& isPossiblePrime) {
    bool isPrimeCandidate = true;
    for (auto i : divisiors)
        if (n % i == 0) {
            isPrimeCandidate = false;
            break;
        }
    isPossiblePrime.set_value(isPrimeCandidate);
}


}

int main() {
    int n;
    std::cin >> n;
    assert(n > 2);
    std::promise<bool> promises[THREADS_NUMBER];
    std::future<bool> futures[THREADS_NUMBER];
    for (int i = 0; i < n; i++)
        futures[i] = promises[i].get_future();
    std::thread threads[THREADS_NUMBER];

    std::vector<int> divisiors[THREADS_NUMBER];
    for (int i = 2; i < n; i++)
        divisiors[i % THREADS_NUMBER].push_back(i);

    for (int i = 0; i < THREADS_NUMBER; i++) 
        threads[i] = std::thread{ [&]() { f(n, divisiors[i], promises[i]); }};

    bool isPrime = true;
    for(auto & f : futures) {
        bool out = f.get();
        isPrime = out && isPrime;
    }

    for (auto& t : threads)
        t.join();

    if(isPrime) std::cout << "PRIME" << std::endl;
    else std::cout << "NOT PRIME" << std::endl;

}

I compile with g++ -std=c++11 -Wall -lpthread on Linux.

like image 265
delabania Avatar asked Dec 15 '25 18:12

delabania


2 Answers

The issue occurs with:

for (int i = 0; i < THREADS_NUMBER; i++) 
    threads[i] = std::thread{ [&]() { f(n, divisiors[i], promises[i]); }};

The [&] captures all variables by reference. This includes promises and i. However, the code inside the lambda is not yet executed. It doesn't run until the operating system has set up the thread and so on. By the time the thread begins execution, the main thread's for loop has finished, and the variable i has ended its lifetime.

But then the thread executes promises[i], where both of those are reference-captures. It looks up the references for both promises and i in order to do this. promises is fine, but i refers to a variable that no longer exists. Probably the segfault is due to i having a garbage value as a result of this lookup and then accessing out of bounds.

Even hoisting int i; out of the loop doesn't fix the problem; then the reference in the lambda does find i, but it has the final value after completing the loop of THREADS_NUMBER, which is out of bounds for the promises array.

To fix the problem, capture i by value:

threads[i] = std::thread{ [&,i]() { f(n, divisiors[i], promises[i]); }};

Then each lambda uses the value of i as it was when the lambda was created.


Note: I think it is OK for a std::thread to have a temporary lambda as constructor parameter, but not sure about that either. The standard does seem to say that the thread constructor copies the functor provided. But all the cppreference examples I searched had a named lambda created first, and then that name given as the constructor parameter to std::thread.

like image 179
M.M Avatar answered Dec 17 '25 08:12

M.M


Problem is due to this line: for (int i = 0; i < n; i++) futures[i] = promises[i].get_future(); - if n>THREADS_NUMBER then it try to read/write from/to promises/futures that was not allocated.

like image 44
Yatima Avatar answered Dec 17 '25 07:12

Yatima



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!