Thursday, December 29, 2011

Inspiration code - Final part

The last of these three parts summary is about _thread and Result structures.

_thread is a just a container for pthread_t and pthread_attr_t thread variables. It provides a wrapper for pthread_create and pthread_detach functions, and a member variable for storing the called function return value... However the most important task accomplished by this structure is reference counting.

template <typename T> struct _thread
{
    // This struct will hold the return value of the thread called func.
    
    _thread() : counter(0)
    {
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    }

    ~_thread() { pthread_detach(thd); }

    T result;
    pthread_t thd;
    pthread_attr_t attr;
    volatile int counter;

    int join() { return pthread_join(thd, NULL); }
    int start(void*(f)(void*), void* v)
    {
        return pthread_create(&thd, &attr, f, v);
    }
    
    // Atomic function for add and sub
    int inc() { return __sync_fetch_and_add(&counter, 1); }
    int dec()
    {
        if (__sync_fetch_and_sub(&counter, 1) == 0)
            delete this;
        return counter;
    }

    private:
    _thread(const _thread&);
    _thread& operator=(const _thread&);
};

_thread has both inc/dec member functions that are called everytime the structure instance is referenced/dereferenced by some other object. When the dec member function is called and the counter becomes zero, then the destructor is invoked and _thread is deleted. Also, the destructor calls pthread_detach, so that thread's resources can be freed.

This reference counting mechanism is very important since we want that _help_fn and _help_st saves the computation results in a place from which we can fetch the result...

To clarify: we can't just launch the thread (that executes _help_fn), save the results and delete everything. We need to be sure that we are deleting the result at the right time.

This is why, when a new thread is created, the corresponding _thread object is referenced both by a _help_st and a Result object. In this way, at the end of _help_fn, when _help_st is deleted, the dec function of _thread object is called by _help_st destructor...
But _thread object is deleted only if also the corresponding Result object is already deleted.

template <typename T> struct Result
{

    Result(_thread<T>* thd) : thd(thd)
    {
        thd->inc();
    }

    Result(const Result<T>& o)
    {
        thd->inc();
        thd = o.thd;
    }

    Result<T>& operator=(const Result& o)
    {
        o.thd->inc();
        thd->dec();
        thd = o.thd;
        return *this;
    }

    T value()
    {
        switch (thd->join())
        {
            case 0:
              break;
            case EINVAL:
              throw std::runtime_error("EINVAL on pthread_join");
              break;
            case EDEADLK:
              throw std::runtime_error("EDEADLK on pthread_join");
              break;
            case ESRCH:
              // Thread already exited 
              break;
        }
        return thd->result;
    }

    ~Result()
    {
        thd->dec();
    }

    _thread<T>* thd;
}

The Result object is the one that is returned to the user who started a new thread. So, if the user keep it, he can fetch the return value through the Result object.
Otherwise the Result object is automatically destroyed and corresponding _thread object is deleted when dec is called by _help_st destructor.

To close this last part, here are the static methods of Thread class for creating a new thread that runs a function, a functor or an instance method having one argument. The signature is similar for functions, functors, and instance methods having more than one arument.
As you see the return value of these function is a Result object.


    template <typename T, typename O, typename I0> static Result<T>
    run(O obj, I0 a0)
    {
        _functor1<T, O, I0> o(obj, a0);
        return Result<T>(_start<T>(o));
    }

    template <typename T, typename I0> static Result<T>
    run(T(*fun)(I0), I0 a0)
    {
        _functor1<T, T(*)(I0), I0> f(fun, a0);
        return Result<T>(_start<T>(f));
    }

    template <typename T, typename C, typename I0> static Result<T>
    run(C* c, T(C::*fun)(I0), I0 a0)
    {
        _class_functor1<T, C, I0> f(c, fun, a0);
        return Result<T>(_start<T>(f));
    }

Returning Result object is assigned a _thread object, created by _start helper function in Thread class.


    template <typename T, typename F> static _thread<T>*
    _start(const F& functor)
    {
        _thread<T>* mythread = new _thread<T>();
        _help_st<T, F >* h2 = new _help_st<T, F>(mythread, functor);
        mythread->start(_help_fn<_help_st<T, F> >, h2);
        return mythread;
    }

I hope you enjoyed this post serie... If you have question or you need some clarification (maybe due to my poor english), just leave a comment. I will be happy to answer or rewrite the unclear part

Tuesday, December 20, 2011

Inspiration code - Part 2

Since the pthread_create function signature allows running of void*(*)(void*) function type only, I was quite sure on packaging into a struct both the callable object and its args, and pass them to some function matching that signature. Here is the "some function" I named _help_fn:

template <S> void* _help_fn(void* v)
{
    // This function signature match the one needed by
    // pthread_create func.
    S* st = (S*)v;
    st->exec();
    delete st;
    return NULL;
};
The S template parameter is meant to be the type of a package struct. The exec() method from this struct should call any callable type, together with its arguments and, obviously, write somewhere the return value of the call.
This is how I wrote the package struct, named _help_st.

template <typename T, typename I> struct _help_st
{
    _help_st(_thread<T>* t, I f) : functor(f)
    {
        thd = t;
        thd->inc();
    }

    ~_help_st()
    {
        thd->dec();
    }

    I functor;
    _thread<T>* thd;

    void exec()
    {
        thd->result = functor();
    }
};
For now, don't pay too much attention to the _thread member variable... You just need to know that this member variable holds the result of thread's computations.
I assigned exec() member function just the task of storing the returned value by a some callable object. The return value type is told by template parameter T. Then, the dirty job of calling the function with all of its args is left to a functor object of type I.

I didn't find any other way than writing as many functors as needed to match all of the previously told callable types.
This is the functor for instance method pointers receiving one arg:

template <typename T, typename C, typename I0> struct _class_functor1
{
    _class_functor1(C* c, T(C::*m)(I0), I0 a0) : m(m), c(c), a0(a0) {}
    T operator()() { return (c->*m)(a0); }
    T(C::*m)(I0);
    C* c;
    I0 a0;
}
And this is the functor for all the other kinds of callable objects receiving one arg:

template <typename T, typename O, typename I0> struct _functor1
{
    _functor1(O obj, I0 a0) : o(obj), a0(a0) {}
    T operator()() { return o(a0); }
    O o;
    I0 a0;
}
I needed a special functor object like _class_functor1 for handling instance methods. This is because C++ don't provide a way to store the callable result of (c->*m).

Monday, December 19, 2011

Inspiration code

A couple of week ago I run into Modern C++ Design, a book from Andrei Alexandrescu. I read it all the way in just a few days. That was so fascinating! This book shows you the unknown and magic power of template metaprogramming... a kind of avada kedavra of C++.

I've got uncertain reviews from my colleagues about this book... But my opinion is definitely a ten out of ten.

But now, let's get to the topic! Just a few day ago, I started writing some code for one of my so-called "funprojects". A snippet of code contained in thread.h file to wraps pthreads functions with a Thread class. After few attempts I decided that my Thread class should be able to execute everything that is a callable in C++.

From Modern C++ Design, here is the list of entities that support operator().
  • C-like functions
  • C-like pointers to functions
  • References to functions
  • Functors (object that defines operator() )
  • The result of applying operator .* or operator ->* having a pointer to a member function in the right-hand side of the expression.
The behavior that I was trying to achieve for any of them was

RETURN_TYPE result = Thread::run(some_callable, arg1, arg2, ...);

And this is what I've got in the end
// main.cpp
#include <iostream>
#include "thread.h"
int myfun(int i)
{
    std::cout << "myfun received: " << i << std::endl;
    return i*2;
}

class myclass
{
public:

    myclass(int i) : i(i) {}

    int mymember(int k)
    {
        std::cout << "mymember received: " << k << std::endl;
        return i*2;
    }
    int i;

    int operator()(int j)
    {
        std::cerr << "operator received: " << j << std::endl;
        return i*2;
    }

};

int main(int argc, char** argv)
{

    int (*mypt)(int) = &myfun;
    int (&myref)(int) = myfun;
    myclass mc(5);

    // Call to function
    Result<int> r0 = Thread::run(myfun, 0);
    std::cout << "retval:" << r0.value() << std::endl;

    // Call to function pointer
    Result<int> r1 = Thread::run(mypt, 1);
    std::cout << "retval:" << r1.value() << std::endl;

    // Call to function reference
    Result<int> r2 = Thread::run(myref, 2);
    std::cout << "retval:" << r2.value() << std::endl;

    // Call to functor
    Result<int> r3 = Thread::run<int>(mc, 3);
    std::cout << "retval:" << r3.value() << std::endl;

    // Call to member function pointer
    Result<int> r4 = Thread::run(&mc, &myclass::mymember, 4);
    std::cout << "retval:" << r4.value() << std::endl;

    return 0;
}

In the next post I'm going to show some details of the code in thread.h.

Want to compile and run this code?!

git clone git://github.com/cybercase/funproject.git
cd funproject/other
g++ concurrent.cpp -o concurrent -Wall # add -lpthread if you are on a linux system