Simplest threaded example

Horacio Sanson hsanson at gmail.com
Thu Jul 29 04:28:46 CEST 2010


After reading several times the documentation/mailing list this is the simplest
threading model I found to work with libev (C++):

#define EV_STANDALONE 1
#define EV_FEATURES 8
#define EV_USE_EPOLL 1
#define EV_PREPARE_ENABLE 1
#define EV_IDLE_ENABLE 1
#define EV_SIGNAL_ENABLE 1
#define EV_CHILD_ENABLE 1
#define EV_USE_STDEXCEPT 0
//#define EV_CONFIG_H <config.h>
#include <ev++.h>
#include "ev.c"

#include <boost/thread.hpp>

#include <iostream>
#include <string>
#include <sstream>

class Server
{
  private:

    struct ev_loop *m_loop;
    mutable boost::mutex m_mutex;
    mutable boost::mutex m_coutMutex;

    ev::io m_stdinWatcher;
    ev::sig m_sigintWatcher;
    ev::sig m_sigtermWatcher;

    void print() {
      boost::mutex::scoped_lock lock(m_coutMutex);
      std::string input = "";
      std::getline(std::cin, input);
      std::cout << "Thread: " << boost::this_thread::get_id() << " echo: " << input << std::endl;
    }

    void sigint_cb(ev::sig &w, int revents) {
      ev_unloop(m_loop, EVUNLOOP_ALL);
    }

    void stdin_cb(ev::io &w, int revents) {
      m_mutex.unlock();
      print();
      m_mutex.lock();
    }

    void worker_thread() {
      m_mutex.lock();
      pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
      ev_loop(m_loop, 0);
      m_mutex.unlock();
    }

  public:

    Server() {

      m_loop = ev_default_loop(0);

      m_stdinWatcher.set<Server, &Server::stdin_cb>(this);
      m_sigintWatcher.set <Server, &Server::sigint_cb>(this);
      m_sigtermWatcher.set <Server, &Server::sigint_cb>(this);

    }

    ~Server() {
      m_stdinWatcher.stop();
      m_sigintWatcher.stop();
      m_sigtermWatcher.stop();
      ev_default_destroy();
    }

    void lock() {
      m_mutex.lock();
    }

    void unlock() {
      m_mutex.unlock();
    }

    void start() {
      m_stdinWatcher.start(0, ev::READ);
      m_sigintWatcher.start(SIGINT);
      m_sigtermWatcher.start(SIGTERM);

      // Worker threads handle event callbacks and add/remove watchers
      boost::thread_group threads;
      for (int i = 0; i < 2; ++i)
        threads.create_thread(boost::bind(&Server::worker_thread, this));

      threads.join_all();
    }
};

int main(int argc, char **argv)
{
  Server server;
  server.start();
}

This is for a small online board game were most of the requests are short (piece
move/update game state) but some requests need DB access that can take several
milliseconds (~500ms) and some other requests can block for some time waiting
for other players updates/timeouts.


The question would be: is this an acceptable threading model for libev and my
application?

Is this a correct way of doing threading with libev?? because helgrind complains
a lot about possible race conditions with this code but I think is due to boost
and not libev.

Any improvements/comments/fixes are welcome....


-- 
regards,
Horacio Sanson



More information about the libev mailing list