I've created this very small header that allows direct creation of threads from lambdas.
I can't find anything else similar on the net so I want to know whether there are any problems with this that I have not thought of. It is based on tinythread++, but can easily be altered to work with pthread or other threading libraries that can take a void (void*)
(or void* (void*)
) function and a void*
argument for the function to start a thread. Note that this implementation is assuming limited C++0x/11 support, i.e. just lambdas.
#include "tinythread.h"
namespace lthread {
/// implementation details - do not use directly
namespace impl {
template<typename Func>
void use_function_once(void* _f) {
const Func* f = (const Func*)_f;
(*f)();
delete f; // delete - no longer needed
}
template<typename Func>
void use_function(void* _f) {
const Func* f = (const Func*)_f;
(*f)();
}
}
/// Creates a thread based on a temporary function.
/// Copies the function onto the heap for use outside of the local scope, removes from the heap when finished.
template<typename Func>
tthread::thread* new_thread(const Func& f) {
Func* _f = new Func(f); // copy to heap
return new tthread::thread(&impl::use_function_once<Func>,(void*)_f);
}
/// Creates a thread based on a guaranteed persistent function.
/// Does not copy or delete the function.
template<typename Func>
tthread::thread* new_thread(const Func* f) {
return new tthread::thread(&impl::use_function<Func>, (void*)f);
}
}
Example usage:
size_t a = 1;
size_t b = 0;
tthread::thread* t = lthread::new_thread([&] () {
std::cout << "I'm in a thread!\n";
std::cout << "'a' is " << a << std::endl;
b = 1;
});
t->join();
std::cout << "'b' is " << b << std::endl;
delete t;
1 Answer 1
surely you can just use
std::function<void()>
instead of templating on the function type?capturing by reference can go horribly wrong. It's not a bug in your library, just an observation ...
tthread::thread* startthread(size_t a, size_t b) { return lthread::new_thread([&] () { std::cout << "I'm in a thread!\n"; std::cout << "'a' is " << a << std::endl; b = 1; } ); } int main() { tthread::thread *t = startthread(1,2); t->join(); delete t; }
use_function_once
is vulnerable to the function call throwing an exception: you should probably assign it to a smart pointer before calling, and lose the explicit delete.that overload of
new_thread
also has a problem if eithernew
ortthread::thread
can throw: it will leak the heap-allocated Func. You can fix this with a smart pointer too.
-
\$\begingroup\$ I have already made a change to the code - the two
new_thread
functions now have different names - the by reference version was capturing the pointer argument instead of the pointer version and thus didn't compile as intended. \$\endgroup\$Dylan– Dylan2012年09月19日 16:59:56 +00:00Commented Sep 19, 2012 at 16:59 -
\$\begingroup\$ Also, I am fully aware of the point you are making with that snippet, but that also applies to any other deferred running of a lambda function. Users should be aware of this as when using by-reference lambdas in other situations. \$\endgroup\$Dylan– Dylan2012年09月19日 17:01:32 +00:00Commented Sep 19, 2012 at 17:01
(*f)();
should throw? You get a leak. \$\endgroup\$