2

I have a problem when running the following in Visual studio 2015.

#include <thread>
#include <vector>
#include <iostream>
using namespace std;

int main() {

    for (int i = 0; i < 10000; i++) {
        cout << "Loop: " << i << endl;

        vector<thread> threads;
        for (int j = 0; j < 8; j++) {
            try {
                threads.push_back(thread([]() {int a = 4; a++; }));
            }
            catch (const system_error &se) {
                cout << se.what() << endl;
                exit(1);
            }
        }

        for (int j = 0; j < 8; j++) {
            threads.at(j).join();
        }
    }

    return 0;
}

After a few thousand loops have been run the program catches a system_error with the output:

...
3994
3995
3996
3997
3998
resource unavailable try again: resource unavailable try again

I know that there is a maximum number of threads that can be run simultaneously but in this case there's only 8 being run simultaneously after which they're destroyed. Is there a maximum on the total number that can be created?

I have tried running the above on Linux with g++ and it runs fine its only on windows (both visual studio and mingw) that the error occurs. Any help? Thanks.

7
  • push_back copies, you probably want to try again with emplace_back Commented Feb 18, 2017 at 13:37
  • Gave it a go Mgetz, but it made no difference Commented Feb 18, 2017 at 13:39
  • 2
    @SamVarshavchik please don't spout opinionated lies in comments. The fact of the matter is C++ is what the majority of windows is built on and the VC++ team has a very interested customer in WINDIV. Commented Feb 18, 2017 at 13:40
  • 2
    @D.Rouse I would suggest giving this article a read it may illuminate what may be limiting you I would guess you're building 32bit, if you changed your build to 64bit you'll probably achieve your goal. Commented Feb 18, 2017 at 13:41
  • Works fine for me with TDM MinGW 5.1.0 Commented Feb 18, 2017 at 13:43

1 Answer 1

5

What happened here is best described by understanding how threads are created on windows.

Each thread when it's created is given a default 1Mb stack size. You'll notice you're getting to approximately 3998 threads which would correspond to approximately 3.9Gb of used user address space. This is not an accident, as this corresponds to most of the full 4Gb user address space available to a 32bit process under 64bit windows (Kernel space is 64bit). The extra space is where the executable and necessary system DLLs are getting loaded into.

By changing the build to 64bit you've massively expanded that address space. Having 10000 threads with a 1Mb stack is a drop in a bucket and the limiter becomes non-pagable kernel memory although the 1Mb stacks can and will be paged out causing the system to slow to a crawl.

Sign up to request clarification or add additional context in comments.

2 Comments

Sorry, but I'm missing something here... As stated in the original post there should never be more than 8 threads in existence (9 if you include main itself) -- all 8 threads are created and destroyed within the scope of a single outer loop iteration. So why the increasing resource usage? Again, sorry if I've missed the point.
@G.M. because join doesn't mean that the threads are deallocated from an OS perspective (although the thread HANDLE must be closed), just that they join up. Like many things on windows I would suspect that thread destruction is asynchronous, but creation is synchronous. So the OS will gladly let you create as many threads as you like under the understanding you'll manage them. Therefore in my estimation the TEBs are probably waiting for destruction on the next DPC that happens at IPC < DISPATCH.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.