简体   繁体   中英

C++, Clang, system_error: thread constructor failed: Resource temporarily unavailable

#include <atomic>
#include <thread>
#include <iostream>
#include <vector>

std::atomic<int> i (0);


void add_one()
{
    std::this_thread::sleep_for(std::chrono::seconds(1)); // [1]
    ++i;                                                  // [2]
}


int main()
{
    std::vector<std::thread> threads;
    while(i < 10)
    {
        threads.push_back(std::thread(&add_one));
    }                                                    // [3]
    std::cout << "num threads: " << threads.size() << std::endl;
    for(auto& t : threads)
    {
        t.detach();
    }

    std::cout << "i: " << i << std::endl;

    return 0;   
}

There is so much wrong about this code I don't even know how to begin. Originally I just wanted to convince myself that atomic ints are really atomic. So I went about building some code to do this. The code as it stands will give "system_error: thread constructor failed: Resource temporarily unavailable" when run on OSX (compiled with Clang). No error on Windows with visual studios. This is caused by the line [1]. If I move [1] to after [2], no error.

But what is blowing my mind is this [3] should be an infinite loop! I did not know that thread when constructed will start executing the function it was given. I always thought that was thread.join or thread.detach. Is there a way to construct a thread object and tell it not to do anything until I want it to start?

In light of this, it doesn't surprise me that much that at runtime the thread constructor threw a warning because it was waiting for too long, but why does it go away when I move line [1] to after [2]? When I move it?

void add_one()
{
    ++i;
    std::this_thread::sleep_for(std::chrono::seconds(5));
    std::cout << "blah" << std::endl;
}

Blah is never displayed, not even in a garbled, non-thread safe way. It's like it never existed.

On windows the blahs will print.

I'm sorry for the massive confusion that I am facing.

Your program is rapidly creating threads and dies when it reaches some upper limit (2048 threads on my system). It doesn't fail when you switch the lines because now the child threads are immediately incrementing i, which causes the for loop to terminate before everything blows up.

You can't create suspended threads in C++11 (I don't know why. Maybe they wanted to support OSes that don't support such an ability). The proper work-around is to have the threads block on some condition before doing anything else. For learning purposes, though, sleeping for one second like you've done is fine.

but why does it go away when I move line [1] to after [2]?

Simple. With line 1 before line 2 you are making your threads wait for a second before incrementing i . Starting a thread may be expensive, but it doesn't take anywhere close to a second. You are creating lots and lots of threads, all of which are waiting for one second to expire. They will all increment i atomically when the timer expires. Until then, your program is rapidly creating more and more threads. Your program will run out of resources long before any one of those timers expire.

When you move line [1] after line [2], your main loop creates threads that increment i and then sleep. The only affect of the sleep is to delay the call to detach . You'll still create more than ten threads, but not a whole lot more.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM