Luka
Luka

Reputation: 1801

Threads: Fine with 10, Crash with 10000

Can someone please explain why the following code crashes:

int a(int x)
{
    int s = 0;
    for(int i = 0; i < 100; i++)
        s += i;
    return s;
}

int main()
{
    unsigned int thread_no = 10000;
    vector<thread> t(thread_no);

    for(int i = 0; i < 10; i++)
        t[i] = std::thread(a, 10);

    for(thread& t_now : t)
        t_now.join();

    cout << "OK" << endl;
    cin.get();
}

But WORKS with 10 threads? I am new to multithreading and simply don't understand what is happening?!

Upvotes: 0

Views: 2858

Answers (2)

kfsone
kfsone

Reputation: 24269

This creates a vector of 10,000 default-initialized threads:

unsigned int thread_no = 10000;
vector<thread> t(thread_no);

You're running into the difference between "capacity" and "size". You didn't just create a vector large enough to house 10,000 threads, you created a vector of 10,000 threads.

See the following (http://ideone.com/i7LBQ6)

#include <iostream>
#include <vector>

struct Foo {
    Foo() { std::cout << "Foo()\n"; }
};

int main() {
    std::vector<Foo> f(8);
    std::cout << "f.capacity() = " << f.capacity() << ", size() = " << f.size() << '\n';
}

You only initialize 10 of the elements as running threads

for(int i = 0; i < 10; i++)
    t[i] = std::thread(a, 10);

So your for loop is going to see 10 initialized threads and then 9,990 un-started threads.

for(thread& t_now : t)
    t_now.join();

You might want to try using t.reserve(thread_no); and t.emplace_back(a, 10);

Here's a complete example with renaming.

int threadFn(int iterations)
{
    int s = 0;
    for(int i = 0; i < iterations; i++)
        s += i;
    return s;
}

int main()
{
    enum {
        MaximumThreadCapacity = 10000,
        DesiredInitialThreads = 10,
        ThreadLoopIterations = 100,
    };

    vector<thread> threads;
    threads.reserve(MaximumThreadCapacity);

    for(int i = 0; i < DesiredInitialThreads; i++)
        threads.emplace_back(threadFn, ThreadLoopIterations);

    std::cout << threads.size() << " threads spun up\n";

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

    std::cout << "threads joined\n";
}

---- EDIT ----

Specifically, the crash you are getting is the attempt to join a non-running thread, http://ideone.com/OuLMyQ

#include <thread>

int main() {
    std::thread t;
    t.join();
    return 0;
}

stderr

terminate called after throwing an instance of 'std::system_error'
  what():  Invalid argument

I point this out because you should be aware there is a race condition even with a valid thread, if you do

if (t.joinable())
    t.join();

it's possible for 't' to become non-joinable between the test and the action. You should always put a t.join() in a try {} clause. See http://en.cppreference.com/w/cpp/thread/thread/join

Complete example:

int threadFn(int iterations)
{
    int s = 0;
    for(int i = 0; i < iterations; i++)
        s += i;
    return s;
}

int main()
{
    enum {
        MaximumThreadCapacity = 10000,
        DesiredInitialThreads = 10,
        ThreadLoopIterations = 100,
    };

    vector<thread> threads;
    threads.reserve(MaximumThreadCapacity);

    for(int i = 0; i < DesiredInitialThreads; i++)
        threads.emplace_back(threadFn, ThreadLoopIterations);

    std::cout << threads.size() << " threads spun up\n";

    for(auto& t : threads) {
        try {
            if(t.joinable())
                t.join();
        } catch (std::system_error& e) {
            switch (e.code()) {
            case std::errc::invalid_argument:
            case std::errc::no_such_process:
                continue;

            case std::errc::resource_deadlock_would_occur:
                std::cerr << "deadlock during join - wth!\n";
                return e.code();

            default:
                std::cout << "error during join: " << e.what() << '\n';
                return e.code();
            }
        }
    }

    std::cout << "threads joined\n";
}

Upvotes: 8

Caesar
Caesar

Reputation: 9863

You create a vector that has 10000 elements in it, you then populate the first ten and you wait for all the the threads inside the vector to join. Your program crashes because you forgot to set the other 9990.

for(int i = 0; i < 10; i++) // Wrong
for(int i = 0; i < thread_no; i++) // Correct

Upvotes: 3

Related Questions