Index: doc/theses/thierry_delisle_PhD/code/readQ_example/proto-gui/main.cpp
===================================================================
--- doc/theses/thierry_delisle_PhD/code/readQ_example/proto-gui/main.cpp	(revision 73fbe91d62a425ae1635a53f34682279e7767750)
+++ doc/theses/thierry_delisle_PhD/code/readQ_example/proto-gui/main.cpp	(revision 73fbe91d62a425ae1635a53f34682279e7767750)
@@ -0,0 +1,212 @@
+#include "thrdlib/thread.h"
+
+#include <cassert>
+
+#include <algorithm>
+#include <atomic>
+#include <memory>
+#include <vector>
+
+//--------------------
+// Constants
+unsigned nframes;
+unsigned fsize;
+unsigned nproduce;
+
+//--------------------
+// Frame management
+
+class Frame {
+	static const thread_t reset;
+	static const thread_t set;
+	std::atomic<thread_t> rdy_state = { reset };
+	std::atomic<thread_t> rnd_state = { set };
+public:
+	unsigned number;
+	std::unique_ptr<unsigned char[]> data;
+
+private:
+	inline bool wait( thread_t self, std::atomic<thread_t> & state, std::atomic<thread_t> & other ) {
+		bool ret;
+		while(true) {
+			thread_t expected = state;
+			if( expected == set ) { ret = false; goto END; }
+			assert( expected == reset );
+			if( std::atomic_compare_exchange_strong( &state, &expected, self) ) {
+				thrdlib_park( self );
+				ret = true;
+				goto END;
+			}
+		}
+		END:
+		assert( state == set );
+		assert( other != set );
+		state = reset;
+		return ret;
+	}
+
+	inline bool publish(  std::atomic<thread_t> & state ) {
+		thread_t got = std::atomic_exchange( &state, set );
+		assert( got != set );
+
+		if( got == reset ) return false;
+
+		thrdlib_unpark( got );
+		return true;
+	}
+
+public:
+	inline bool wait_rendered( thread_t self ) {
+		return wait( self, rnd_state, rdy_state );
+	}
+
+	inline bool wait_ready   ( thread_t self ) {
+		return wait( self, rdy_state, rnd_state );
+	}
+
+	inline bool publish() {
+		return publish( rdy_state );
+	}
+
+	inline bool release() {
+		return publish( rnd_state );
+	}
+};
+
+const thread_t Frame::reset = nullptr;
+const thread_t Frame::set   = reinterpret_cast<thread_t>(1);
+
+std::unique_ptr<Frame[]> frames;
+volatile unsigned last_produced = 0;
+
+//--------------------
+// Threads
+thread_t volatile the_stats_thread = nullptr;
+
+inline void fence(void) {
+	std::atomic_thread_fence(std::memory_order_seq_cst);
+}
+
+struct {
+	struct {
+		volatile unsigned long long   parks = 0;
+		volatile unsigned long long unparks = 0;
+	} sim;
+	struct {
+		volatile unsigned long long   parks = 0;
+		volatile unsigned long long unparks = 0;
+	} rend;
+
+	struct {
+		volatile unsigned long long ran = 0;
+		volatile unsigned long long saw = 0;
+	} stats;
+} thrd_stats;
+
+void Stats( thread_t self ) {
+	the_stats_thread = self;
+	fence();
+	thrdlib_park( self );
+
+	std::vector<bool> seen;
+	seen.resize(nproduce, false);
+
+	while(last_produced < nproduce) {
+		thrdlib_yield();
+		thrd_stats.stats.ran++;
+		if( last_produced > 0 ) seen.at(last_produced - 1) = true;
+	}
+
+	thrd_stats.stats.saw = std::count(seen.begin(), seen.end(), true);
+}
+
+void Simulator( thread_t self ) {
+	for(unsigned i = 0; i < nproduce; i++) {
+		auto & frame = frames[i % nframes];
+		// Wait for the frames to be rendered
+		if( frame.wait_rendered( self ) ) {
+			thrd_stats.sim.parks++;
+		}
+
+		// Write the frame information
+		frame.number = i;
+		for( unsigned x = 0; x < fsize; x++ ) {
+			frame.data[x] = i;
+		}
+		std::cout << "Simulated " << i << std::endl;
+		last_produced = i+1;
+
+		// Publish it
+		if( frame.publish()  ) {
+			thrd_stats.sim.unparks++;
+		}
+	}
+}
+
+void Renderer( thread_t self ) {
+	thrdlib_unpark( the_stats_thread );
+	for(unsigned i = 0; i < nproduce; i++) {
+		auto & frame = frames[i % nframes];
+		// Wait for the frames to be ready
+		if( frame.wait_ready( self ) ) {
+			thrd_stats.rend.parks++;
+		}
+
+		// Render the frame
+		unsigned total = 0;
+		for( unsigned x = 0; x < fsize; x++ ) {
+			total += frame.data[x];
+		}
+
+		std::cout << "Rendered " << i << std::endl;
+		assert(total == i * fsize);
+
+		// Release
+		if( frame.release() ) {
+			thrd_stats.rend.unparks++;
+		}
+	}
+
+}
+
+
+
+int main() {
+	nframes  = 3;
+	fsize    = 1000;
+	nproduce = 60;
+
+	frames.reset(new Frame[nframes]);
+	for(unsigned i = 0; i < nframes; i++) {
+		frames[i].number = 0;
+		frames[i].data.reset(new unsigned char[fsize]);
+	}
+	std::cout << "Created frames" << std::endl;
+
+	thrdlib_setproccnt( 2 );
+
+	thread_t stats     = thrdlib_create( Stats     );
+	std::cout << "Created Stats Thread" << std::endl;
+	while( the_stats_thread == nullptr ) thrdlib_yield();
+	std::cout << "Creating Main Threads" << std::endl;
+	thread_t renderer  = thrdlib_create( Renderer  );
+	// while(true);
+	thread_t simulator = thrdlib_create( Simulator );
+
+	std::cout << "Running" << std::endl;
+
+	thrdlib_join( simulator );
+	thrdlib_join( renderer  );
+	thrdlib_join( stats     );
+
+	std::cout << "----------" << std::endl;
+	std::cout << "# Parks" << std::endl;
+	std::cout << "  Renderer   park: " << thrd_stats. sim.  parks << std::endl;
+	std::cout << "  Renderer unpark: " << thrd_stats. sim.unparks << std::endl;
+	std::cout << " Simulator   park: " << thrd_stats.rend.  parks << std::endl;
+	std::cout << " Simulator unpark: " << thrd_stats.rend.unparks << std::endl;
+
+	std::cout << "Stats thread" << std::endl;
+	std::cout << " Ran             : " << thrd_stats.stats.ran << " times" << std::endl;
+	std::cout << " Saw             : " << thrd_stats.stats.saw << " (" << ((100.f * thrd_stats.stats.saw) / nproduce) << "%)" << std::endl;
+}
