Created
January 9, 2012 09:53
-
-
Save jefftrull/1582257 to your computer and use it in GitHub Desktop.
Example of producer-consumer for Ruby interpreter with separate thread in C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example of running Ruby in a separate thread | |
// 2012-01-08 by Jeff Trull <jetrull@sbcglobal.net> | |
#include <iostream> | |
#include <queue> | |
#include <string> | |
#include <set> | |
#include <boost/thread.hpp> | |
#include <boost/thread/mutex.hpp> | |
#include "ruby.h" | |
// inter-thread communication by means of locked queue | |
typedef std::pair<std::string, int> message; // could be anything | |
static std::queue<message> command_queue, result_queue; // producer/consumer queue | |
static boost::mutex command_lock, result_lock; // a single lock to access | |
// create some functions for Ruby to access the communication queues | |
void ruby_main(int argc, char** argv) { | |
// set up interpreter | |
ruby_sysinit(&argc, &argv); | |
RUBY_INIT_STACK; | |
ruby_init(); | |
ruby_init_loadpath(); | |
// some data for us to use | |
rb_eval_string("$x = 1"); | |
rb_eval_string("$y = 2"); | |
// run eval loop | |
message msg("dummy command", 0); | |
do { | |
boost::mutex::scoped_lock sl(command_lock); | |
if (!command_queue.empty()) { | |
msg = command_queue.front(); | |
if (msg.second > 0) { | |
rb_eval_string(msg.first.c_str()); | |
// send results to main thread | |
boost::mutex::scoped_lock sl_result(result_lock); | |
result_queue.push(std::make_pair("result", msg.second)); | |
} | |
command_queue.pop(); | |
} | |
} while (msg.second >= 0); | |
// cleanup ruby | |
ruby_cleanup(0); | |
} | |
// just to show you can do it from another function | |
void send_command(const message& msg) { | |
boost::mutex::scoped_lock sl(command_lock); // automatically unlocks at end of block | |
command_queue.push(msg); | |
} | |
int main(int argc, char** argv) { | |
// launch Ruby thread | |
boost::shared_ptr<boost::thread> ruby_thread(new boost::thread(ruby_main, argc, argv)); | |
// send it some messages | |
{ | |
boost::mutex::scoped_lock sl(command_lock); | |
command_queue.push(std::make_pair(std::string("puts $x"), 1)); | |
command_queue.push(std::make_pair(std::string("puts $y"), 2)); | |
command_queue.push(std::make_pair(std::string("puts $x+$y"), 3)); | |
} | |
// send it a message from another function | |
send_command(std::make_pair(std::string("puts 2*$y"), 4)); | |
// wait for replies | |
std::set<int> results_back; | |
while (!((results_back.find(1) != results_back.end()) && | |
(results_back.find(2) != results_back.end()) && | |
(results_back.find(3) != results_back.end()) && | |
(results_back.find(4) != results_back.end()))) { | |
// not all commands have finished; check for more | |
boost::mutex::scoped_lock sl(result_lock); | |
if (!result_queue.empty()) { | |
message result = result_queue.front(); | |
result_queue.pop(); | |
results_back.insert(result.second); | |
} | |
} | |
// we have all replies; send termination message (can also kill thread...) | |
send_command(std::make_pair(std::string("stop work now"), -1)); | |
// "join" ruby thread to wait for completion | |
ruby_thread->join(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment