mreff555
mreff555

Reputation: 1111

std::thread maximum concurrent threads

I'm trying to understand a few basic concepts in std::thread, which I am still not confident about. The underlying question is:

what is actually happening when I exceed the value of std::thread::hardware_concurrency(), like I did below?

I know the method is just a hint, but in this case 8 should be accurate. I see no warnings or errors, so what is actually happening?

I suspect this has something do with my lack of understanding of join() and detach(), which leads me to my second question.

I know that if I spin up threads without either a join() or detach() that I will get runtime errors. As I understand it from reading and observations, join() causes the thread to block until it has finished execution, while detach() does basically the opposite, allowing the thread to run wild until it finishes, potentially opening a can of worms if that thread doesn't terminate on its own.

Based on what I observed, it seems that usage of join() and detach() are mutually exclusive. Is this wrong? Why would I ever need to use join() and detach() on the same thread?

As far as my first question goes, I cannot even begin to guess. I expected some type of runtime error, or some more obvious forced blocking.

#include <ctime>
#include <cstdlib>
#include <iostream>
#include <thread>
#include <vector>

std::vector<unsigned> getNumbers(unsigned n)
{
    std::vector<unsigned> out;
    while(n > 0)
    {
        out.push_back(rand());
        n--;
    }
    return out; 
}

int main() {
    srand(time(nullptr));
    std::vector<std::thread> threads;
    unsigned maxThreads = std::thread::hardware_concurrency();
    std::cout << "Max threads: " << maxThreads << std::endl;

    unsigned tooManyThreads = maxThreads + 5;

    for(auto i = 0; i < tooManyThreads; i++)
    {
        threads.push_back(std::thread(getNumbers,(rand() % 10000 + 1)));
        std::cout << "Starting thread " << i << " (" 
            << threads.back().get_id() << ")" << std::endl;
        threads.back().detach();
    }

    for(auto i = 0; i < tooManyThreads; i++)
    {   
        if(threads.at(i).joinable())
        {
            threads.at(i).join();
            std::cout << "Joining " << i << std::endl;
        }
    }
    return 0;
} 

Upvotes: 2

Views: 6101

Answers (2)

Alecto
Alecto

Reputation: 10740

At any given time there are several thousand threads running on your computer. Most of them come from other programs or processes, of which there are hundreds or thousands running in the background. (You can see them if you open TaskManager in windows, or type htop into a Linux command prompt).

So what is std::thread::hardware_concurrency? It’s the number of threads that can execute simultaneously. If you have 8 logical cores, you can only ever execute 8 threads simultaneously. All other threads are “paused”, at least until it’s their turn to run.

This may sound like a contradiction: how is it possible to have thousands of threads without thousands of cores? The answer is that the Operating System schedules threads. Each active thread gets a turn to run, and it happens sufficiently quickly that humans don’t notice delays, but those threads aren’t actually executing simultaneously.

Basically, std::thread::hardware_concurrency tells you the maximum possible speed up from using threads. If you have 8 cores, the maximum speed up from parallelizing using threads is 8x. It’s fine to start more threads than that, and many programs do so because they’re designed so that different threads handle different types tasks (like one thread may read/write files, and another thread may control the GUI, and another thread may process stuff in the background, and another thread may talk to the network), but it won’t actually make your program run faster.

Upvotes: 6

Peter Bell
Peter Bell

Reputation: 370

You seem to be confused about what "thread" means in this context. There are two kinds of thread: std::thread is a software thread, while std::thread::hardware_concurrency() returns the number of hardware threads.

A sofware thread doesn't need a dedicated hardware thread, the operating system can and will schedule different software threads to share the same hardware threads. In fact, there are usually several orders of magnitude more software threads than there are hardware threads on the machine.

Upvotes: 5

Related Questions