Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@jefftrull
Created January 9, 2012 09:53
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jefftrull/1582257 to your computer and use it in GitHub Desktop.
Save jefftrull/1582257 to your computer and use it in GitHub Desktop.
Example of producer-consumer for Ruby interpreter with separate thread in C++
// 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