From 2aab2491aacafe4804a8a71970d9b4bd81680c59 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 2 Jan 2009 08:02:27 +0100 Subject: [PATCH] deal with a race regarding argument passing --- src/lib/thread-wrapper.hpp | 54 +++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/src/lib/thread-wrapper.hpp b/src/lib/thread-wrapper.hpp index 8c90295b4..b927f3d51 100644 --- a/src/lib/thread-wrapper.hpp +++ b/src/lib/thread-wrapper.hpp @@ -25,27 +25,36 @@ #define LUMIERA_THREADWRAPPER_H -#include "backend/threads.h" #include "include/nobugcfg.h" +#include "lib/sync.hpp" + +extern "C" { +#include "backend/threads.h" +} #include #include namespace lumiera { - + using std::tr1::bind; using std::tr1::function; using std::tr1::placeholders::_1; + using lib::Sync; + using lib::NonrecursiveLock_Waitable; + /** * A thin convenience wrapper for dealing with threads, * as implemented by the backend (on top of pthread). * Using this wrapper... * - helps with passing data to the function executed in the new thread - * - allows to bind to various kinds of functions + * - allows to bind to various kinds of functions including member functions * - supports integrating with an existing object monitor based lock (planned) + * The new thread starts immediately within the ctor; after returning, the new + * thread has already copied the arguments and indeed actively started to run. * * @note this class is \em not a thread handle. Within Lumiera, we do all of * our thread management such as to avoid using global thread handles. @@ -56,35 +65,56 @@ namespace lumiera { * was just being shaped. It may well be possible that such a wrapper * is superfluous in the final application. Re-evaluate this! */ - class Thread : boost::noncopyable + class Thread + : public Sync, + boost::noncopyable { + volatile bool started_; + typedef function Operation; + Operation const& operation_; static void run (void* arg) { ASSERT (arg); - Operation doIt_ = *reinterpret_cast(arg); + Thread* startingWrapper = reinterpret_cast(arg); + Operation _doIt_(startingWrapper->operation_); + { + Lock sync(startingWrapper); + startingWrapper->started_ = true; + sync.notify(); // handshake signalling we've gotten the parameter + } - doIt_(); + _doIt_(); // execute the actual operation in the new thread } public: - Thread (Literal& purpose, Operation operation, struct nobug_flag *logging_flag = &NOBUG_FLAG(operate)) + Thread (Literal& purpose, Operation const& operation, struct nobug_flag *logging_flag = &NOBUG_FLAG(operate)) + : started_(false), + operation_(operation) { + Lock sync(this); + LumieraThread res = lumiera_thread_run ( LUMIERA_THREAD_INTERACTIVE , &run // invoking the run helper and.. - , &operation // passing the actual operation as parameter + , this // passing this start context as parameter , 0 // no condition variable provided (for now...) , purpose.c_str() , logging_flag ); + + if (!res) + throw error::State("failed to create new thread."); + + // make sure the new thread had the opportunity to take the Operation + // prior to leaving and thereby possibly destroying this local context + sync.wait (started_); } }; - - - -} // namespace lumiera + + + } // namespace lumiera #endif