
Howard Hinnant wrote:
New use case:
vector<thread> v; ... fill with threads ... for (auto i = v.begin(), e = v.end(); i != e; ++i) if (i_feel_like_it) i->detach(); ... // need new thread now, go look for a detached one and use it auto i = v.begin(); for (auto e = v.end(); i != e; ++i) if (i->is_detached()) // N2184 spells this i->get_id() == thread::id() break; if (i != v.end()) *i = std::thread(f); // recycle detached thread else v.push_back(std::thread(f));
I was thinking of something along these lines, but it still seems contrived to me. There is no reason to reuse an std::thread _object_ because you gain no efficiency from that (as opposed to reusing a thread). So I'd use something like:
for (auto i = v.begin(), e = v.end(); i != e; ++i) if (i_feel_like_it) i->detach(); remove_i_from_v();
and then just add new threads with push_back... If I'm not interested in *i, I see no reason to keep it in the vector - if I use v.size() as an indication of the number of my active threads, this would skew the results. There's also: for (auto i = v.begin(), e = v.end(); i != e; ++i) if( i->try_join() ) remove_i_from_v(); (ignoring invalidation for the purposes of the pseudocode :-) ) which is useful if I want to keep an eye on 'my' threads but need v.size() to not include dead ones. In this case, I can decide whether a detached thread still counts against 'mine' by leaving or not leaving it in v after detach. In a less forgiving model such as N2178, the original example is just erase_if( v, feel_like_it_predicate ); since it has an implicit detach, although I admit that cancel on destroy is useful in other scenarios and have no strong preference for one over the other.