Mercurial > love-experiments
diff src/modules/thread/Channel.cpp @ 1197:1a59c21cd2f3 minor
Add Channel:supply(), a blocking version of Channel:push()
| author | Bart van Strien <bart.bes+projects@gmail.com> |
|---|---|
| date | Sun, 27 Jan 2013 20:04:16 +0100 |
| parents | fc7143cc0818 |
| children | ee1448bb9680 |
line wrap: on
line diff
--- a/src/modules/thread/Channel.cpp Sun Jan 27 19:15:55 2013 +0100 +++ b/src/modules/thread/Channel.cpp Sun Jan 27 20:04:16 2013 +0100 @@ -22,6 +22,30 @@ #include <map> #include <string> +namespace +{ + union uslong + { + unsigned long u; + long i; + }; + + // target <= current, but semi-wrapsafe, one wrap, anyway + inline bool past(unsigned int target, unsigned int current) + { + if (target > current) + return false; + if (target == current) + return true; + + uslong t, c; + t.u = target; + c.u = current; + + return !(t.i < 0 && c.i > 0); + } +} + namespace love { namespace thread @@ -41,14 +65,14 @@ } Channel::Channel() - : named(false) + : named(false), sent(0), received(0) { mutex = newMutex(); cond = newConditional(); } Channel::Channel(const std::string &name) - : named(true), name(name) + : named(true), name(name), sent(0), received(0) { mutex = newMutex(); cond = newConditional(); @@ -68,10 +92,10 @@ namedChannels.erase(name); } -void Channel::push(Variant *var) +unsigned long Channel::push(Variant *var) { if (!var) - return; + return 0; Lock l(mutex); var->retain(); // Keep a reference to ourselves @@ -79,7 +103,24 @@ if (named && queue.empty()) retain(); queue.push(var); - cond->signal(); + cond->broadcast(); + + return ++sent; +} + +void Channel::supply(Variant *var) +{ + if (!var) + return; + + unsigned long id = push(var); + + mutex->lock(); + while (!past(id, received)) + { + cond->wait(mutex); + } + mutex->unlock(); } Variant *Channel::pop() @@ -91,6 +132,9 @@ Variant *var = queue.front(); queue.pop(); + received++; + cond->broadcast(); + // Release our reference to ourselves // if we're empty and named. if (named && queue.empty())
