Can you count on your counter?

History

A while ago in a small OCaml-script I needed a counter.
I wasn't sure, how to program it.

Should I use

Because I'm not one of those object-fetishists, but also didn't wanted to use a module for it, I decided for using a closure.
BTW, when thinking abour objects, well, in OCaml I could have used anonymous objects, and possibly this would be the way I would go it the next time, because this would help me avoiding the unneccessary definition of a class...
...I just only needed one counter at that script.

Leisure Time

Some days ago I came along some C-programming and had some leisure time to do something, I would like to explore.
So I thought about: how would I do such a counter in C?

What I needed was a way to create that counter easily, as well as passing it around. So I thought, it possibly would make sense to do it in an object-like datastructure.
Something like an object... but... in C you have none provided by the language itself.
But there are ways to achieve similar things: one can use a structure, that holds pointers to the data as well as to the functions/operations (methods) that are used together with that data.

The declarations for the counter,
counter.h:


typedef struct _counter *  COUNTER_P;

typedef struct _counter {
  int  val;                   /* counter-value */
  int  (*get)  ( COUNTER_P ); /* function to get the value of the counter */
  void (*clear)( COUNTER_P ); /* function to clear the value of the counter */
  void (*incr) ( COUNTER_P ); /* function to increment the value of the counter */
  void (*decr) ( COUNTER_P ); /* function to decrement the value of the counter */
  void (*prt)  ( COUNTER_P ); /* function to print the value of the counter     */
  char* text;                 /* text to print before the value */
} COUNTER;


/* ----------------------------------------------------------- */
/* prototypes for the visible constructor/destructor functions */
/* ----------------------------------------------------------- */
COUNTER* new_counter( char* txt );
void free_counter( COUNTER* ctrp );
  

Now look at the implementation of the counter-stuff
counter.c:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include "counter.h"


/* ------------------------------------- */
/* get the value of the counter via the  */
/* returnvalue from this function.       */
/* ------------------------------------- */
static int get( COUNTER_P ctrp )
{
  return ctrp->val;
}

/* ---------------------------------------------- */
/* clear the counter (means: setting value to 0 ) */
/* ---------------------------------------------- */
static void clear( COUNTER_P ctrp )
{
  ctrp->val = 0;
  return;
}

/* ---------------------------- */
/* increment the counter by one */
/* ---------------------------- */
static void incr( COUNTER_P ctrp )
{
  ++ctrp->val;
  return;
}

/* ---------------------------- */
/* decrement the counter by one */
/* ---------------------------- */
static void decr( COUNTER_P ctrp )
{
  --ctrp->val;
  return;
}

/* --------------------------------------------------- */
/* Print the value of the counter, followed by "\n" .  */
/* if there is a text assigned to ctrp->text, print it */
/* before the counter-value is printed.                */
/* --------------------------------------------------- */
static void prt( COUNTER_P ctrp )
{
  if( ctrp->text )
    printf("%s", ctrp->text );

  printf("%d\n", ctrp->val);
  return;
}



/* ----------------------------------------------------- */
/* default-values are set by this template (convenience) */
/* ----------------------------------------------------- */
static COUNTER vorlage = { 0, get, clear, incr, decr, prt };



/* ======================================= */
/* Create a new counter.                   */
/* ======================================= */
/* This function is visible to the outside */
/* ======================================= */
COUNTER* new_counter( char* txt )
{
  COUNTER* counter = calloc( 1, sizeof(COUNTER) );

  if( counter == NULL )
    return NULL;

  memcpy( counter, &vorlage, sizeof(COUNTER) );

  if( txt != NULL )
    counter->text = strdup(txt);

  return counter;
}


/* ======================================= */
/* Delete a counter.                       */
/* ======================================= */
/* This function is visible to the outside */
/* ======================================= */
void free_counter( COUNTER* ctrp )
{
  if( ctrp == NULL )
    return;

  if( ctrp->text != NULL )
    free( ctrp->text );

  free( ctrp );

  return;
}


  

Here (above) you can see the implementations of the functions, that provide the functionality.
In OO-languages you would talk about methods, but we are using ANSI-C here and so we can call it functions. We have no object here, but a thingy that is quite similar to an object.
But that's rather a discussion for philosophers.
But let me add just one note: we would have a more-close-to-OO style, when using one function, which represents the object (instead of one function for each method), and one parameter, that selects the functionality (like a message).

And now an example of usage, which I used to play around,
main.c:


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#include "counter.h"


/* ----------------------------------------------- */
/* this function is used as a bew counter-function */
/* it can be used to replace the default-printer   */
/* ----------------------------------------------- */
void my_counter_printer( COUNTER_P ctrp )
{
  printf("Ich bin der neue Counter-Printer.\tValue: %d\n", ctrp->val );
  return;
}


/* ------------------------------------------------------------------ */
/* Action passed around: we clear the counter from "somewehere else", */
/* showing that we can pass around the functionality via the pointer. */
/* ------------------------------------------------------------------ */
void sub_macht_counter_platt( COUNTER_P ctrp )
{
  ctrp->clear(ctrp);
  return;
}


/* ======================================== */
/* demonstrate how to use the counter-stuff */
/* ======================================== */
int main()
{
  COUNTER* ctr_a = NULL;
  COUNTER* ctr_b = NULL;



  ctr_a = new_counter("Hello ");
  if( ctr_a == NULL )
    abort();
  ctr_a->incr(ctr_a);
  ctr_a->prt(ctr_a);

  ctr_b = new_counter("Counter B: ");
  if( ctr_b == NULL )
    abort();
  ctr_b->incr(ctr_b);
  ctr_b->prt(ctr_b);

  ctr_b->incr(ctr_b);
  ctr_b->incr(ctr_b);
  ctr_b->incr(ctr_b);

  ctr_b->incr(ctr_b);
  ctr_b->incr(ctr_b);
  ctr_b->incr(ctr_b);
  ctr_b->incr(ctr_b);
  ctr_b->incr(ctr_b);


  ctr_a->prt(ctr_a);
  ctr_b->prt(ctr_b);

printf("----------------------------------\n");
  ctr_b->prt = my_counter_printer;
  ctr_a->prt(ctr_a);
  ctr_b->prt(ctr_b);
printf("----------------------------------\n");

  ctr_a->prt(ctr_a);
  ctr_b->prt(ctr_b);

  sub_macht_counter_platt( ctr_b );
  ctr_b->prt(ctr_b);



  free_counter( ctr_a ); ctr_a = NULL;
  free_counter( ctr_b ); ctr_b = NULL;


  return 0;
}
  

As you can see above, it is also possible to replace one function by a new definition. I have done this for the printer-function and replaced the original one by the new printer-function my_counter_printer().
This is, what in OO-languages would be called overloading: your old method will be no longer available, instead you replace the prt-method by a new method. Or better (more OO-jargon like): "for the prt-message a different method will be called."

Making More Out Of It?

OK, now I had converted the OCaml-closure to an ANSI-C Object-like thingy.
This was a nice pastime.

But what now?

Now I have such a nice counter, which also can be passed around, but who would have a need of it?
Well, it's a convenient way of using a counter. This might be nice for some cases of programming.
But: why not using a function that has a static int-variable and works on it? Ok, if one needs only one such counter (as was in my first need), this would be completely ok; but only, if reentrance would not be needed.
Using such a structure-based approach brings the advantage of re-entrance-ability, as well as the possibility to have more than one counter available.
Also calling it from seomwhere in your code is easy, because it's object-like and needs no functions from somewhere else but have all it needs in it's own bag.

When we want to pass some counters around, this is fine. When we pass one counter around to many places, each will be worked on seperately and no problems occur.
But the one big advantage of such an encapsulation is, to have the possibility not only to spread it over the code, which uses it... it is in principially also possible to spread it timely-parallelized, by using threads for example.
And especially here, this approach is quite useful, because ONE poointer can be passed to many places and work at many times, but the value in use (the counter-value) is one value, that all passed references of it are pointing to.
This is quite useful, when for example thinking on Web and I/O.
But to be sure that this really works, one has to protect the data (with a mutex), as is necessary in a multithreaded application. If you would not protect the data, I'm sure, you could not count on your counter.

So now we go that way: Making Mor Out Of It, by making it multithreaded.

Threaded version of counter.h


typedef struct _counter *  COUNTER_P;


typedef struct _counter {
  int  val;                   /* counter-value */
  void (*get)  ( COUNTER_P, int* res ); /* function to get the value of the counter */
  void (*clear)( COUNTER_P ); /* function to clear the value of the counter */
  void (*incr) ( COUNTER_P ); /* function to increment the value of the counter */
  void (*decr) ( COUNTER_P ); /* function to decrement the value of the counter */
  void (*prt)  ( COUNTER_P ); /* function to print the value of the counter     */
  char* text;                 /* a text that will be printed before the counter-value */
  pthread_mutex_t* mutex_p;   /* this mutex is used for all operations on the data */
} COUNTER;


/* ----------------------------------------------------------- */
/* prototypes for the visible constructor/destructor functions */
/* ----------------------------------------------------------- */
COUNTER* new_counter( char* txt );
void free_counter( COUNTER* ctrp );
  

Threaded version of counter.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <pthread.h>


#include "counter.h"


/* --------------------------------------- */
/* get the value of the counter.           */
/* The value will be passed to the memory  */
/* location that is pointed to by "result" */
/* --------------------------------------- */
static void get( COUNTER_P ctrp, int* result )
{
  if( result == NULL )
    return;

  pthread_mutex_lock( ctrp->mutex_p );
    *result = ctrp->val;
  pthread_mutex_unlock( ctrp->mutex_p );

  return;
}

/* ---------------------------------------------- */
/* clear the counter (means: setting value to 0 ) */
/* ---------------------------------------------- */
static void clear( COUNTER_P ctrp )
{
  pthread_mutex_lock( ctrp->mutex_p );
    ctrp->val = 0;
  pthread_mutex_unlock( ctrp->mutex_p );
  return;
}

/* ---------------------------- */
/* increment the counter by one */
/* ---------------------------- */
static void incr( COUNTER_P ctrp )
{
  pthread_mutex_lock( ctrp->mutex_p );
    ++ctrp->val;
  pthread_mutex_unlock( ctrp->mutex_p );
  return;
}

/* ---------------------------- */
/* decrement the counter by one */
/* ---------------------------- */
static void decr( COUNTER_P ctrp )
{
  pthread_mutex_lock( ctrp->mutex_p );
    --ctrp->val;
  pthread_mutex_unlock( ctrp->mutex_p );
  return;
}

/* --------------------------------------------------- */
/* Print the value of the counter, followed by "\n" .  */
/* if there is a text assigned to ctrp->text, print it */
/* before the counter-value is printed.                */
/* --------------------------------------------------- */
static void prt( COUNTER_P ctrp )
{
  pthread_mutex_lock( ctrp->mutex_p );
  if( ctrp->text )
    printf("%s", ctrp->text );

  printf("%d\n", ctrp->val);

  pthread_mutex_unlock( ctrp->mutex_p );
  return;
}



/* ----------------------------------------------------- */
/* default-values are set by this template (convenience) */
/* ----------------------------------------------------- */
static COUNTER vorlage = { 0, get, clear, incr, decr, prt };



/* ======================================= */
/* Create a new counter.                   */
/* ======================================= */
/* This function is visible to the outside */
/* ======================================= */
COUNTER* new_counter( char* txt )
{
  COUNTER* counter = calloc( 1, sizeof(COUNTER) );
  int retval = 0;

  if( counter == NULL )
    return NULL;

  memcpy( counter, &vorlage, sizeof(COUNTER) );

  if( txt != NULL )
    counter->text = strdup(txt);


  counter->mutex_p = calloc( 1, sizeof(pthread_mutex_t) );
  if( counter == NULL )
  {
    free_counter( counter ); /* free's all already calloc't data */
    return( NULL );
  }
    

  retval = pthread_mutex_init( counter->mutex_p, NULL);
  if( retval )
  {
    free_counter( counter ); /* free's all already calloc't data */
    return NULL;
  }

  return counter;
}


/* ======================================= */
/* Delete a counter.                       */
/* ======================================= */
/* This function is visible to the outside */
/* ======================================= */
void free_counter( COUNTER* ctrp )
{
  if( ctrp == NULL )
    return;

  if( ctrp->text != NULL )
    free( ctrp->text );

  if( ctrp->mutex_p != NULL )
  {
    pthread_mutex_destroy( ctrp->mutex_p );
    free( ctrp->mutex_p );
  }


  free( ctrp );

  return;
}

    

Threaded version of main.c


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <pthread.h>

#include "counter.h"




/* -------------------------------------------- */
/* We want to have more then one thread.        */
/* here we define the number of threads to use  */
/* and provide an array of thread-id's,         */
/* to be filled later.                          */
/* -------------------------------------------- */
#define NUM_THREADS 5
pthread_t thread_id_array[ NUM_THREADS ];



/* ----------------------------------------------- */
/* this function is used as a bew counter-function */
/* it can be used to replace the default-printer   */
/* ----------------------------------------------- */
void my_counter_printer( COUNTER_P ctrp )
{
  printf("Ich bin der neue Counter-Printer.\tValue: %d\n", ctrp->val );
  return;
}


/* ------------------------------------------------------------------ */
/* Action passed around: we clear the counter from "somewehere else", */
/* showing that we can pass around the functionality via the pointer. */
/* ------------------------------------------------------------------ */
void sub_macht_counter_platt( COUNTER_P ctrp )
{
  ctrp->clear(ctrp);

  return;
}


/* ---------------------------------------- */
/* A function that can be used by a thread. */
/* ---------------------------------------- */
/* There is a random sleep-time, so that    */
/* the demonstration will not become too    */
/* boring.                                  */
/* ---------------------------------------- */
void* use_counter( void* counter_p )
{
  int loop = 0;
  int sleeptime = 0;
  COUNTER_P counter = counter_p;

  pthread_t self = pthread_self();

  sleeptime = rand()/(RAND_MAX / 4);

  printf("myself: %d | sleeptime: %d | ctr_a: %p\n", self, sleeptime, counter );

  for( loop = 0; loop < 5; loop++ )
  {
    printf("myself: %d | loop: %d\n", self, loop );
    counter->prt(counter);
    counter->incr(counter);
    printf("myself: %d\n", self );
    sleep(sleeptime);
  }

  return NULL;
}



/* ======================================== */
/* demonstrate how to use the counter-stuff */
/* ======================================== */
int main()
{
  pthread_t thread;
  COUNTER* ctr_a = NULL;
  COUNTER* ctr_b = NULL;
  COUNTER* ctr_dummy = NULL;
  size_t idx = 0;
  int retval = 0;

  pthread_mutex_t mutex;


  /* creating counters */
  /* ================= */
  ctr_a = new_counter("Hello ");
  if( ctr_a == NULL )
    abort();
  ctr_a->incr(ctr_a);
  ctr_a->prt(ctr_a);

  ctr_b = new_counter("Counter B: ");
  if( ctr_b == NULL )
    abort();

  /* doing some increments */
  /* --------------------- */
  ctr_b->incr(ctr_b);
  ctr_b->incr(ctr_b);
  ctr_b->incr(ctr_b);

  /* ----------------------------------------------------- */
  /* create threads that use function use_counter and have */
  /* counter ctr_a as argument                             */
  /* ----------------------------------------------------- */
  for( idx = 0; idx < NUM_THREADS; idx++ )
  {
    printf("ctr_a: %p\n", ctr_a );
    retval = pthread_create( &thread_id_array[idx], NULL, use_counter, ctr_a );
    if( retval )
      abort();
    sub_macht_counter_platt( ctr_a ); /* ugly man ;-) */
    printf("%d, %d\n", retval, thread_id_array[idx]);
  }


  sub_macht_counter_platt( ctr_a );

  sleep(2); /* sleeping for a short while */

  /* doing incrementations and printing values of counters */
  /* ----------------------------------------------------- */
  for( idx = 0; idx < 5; idx++ )
  {
    ctr_b->incr(ctr_a);
    ctr_b->incr(ctr_b);
    ctr_b->prt(ctr_b);
    ctr_b->prt(ctr_a);
    sleep(1);
  }

  /* changing the printer of counter A */
  /* --------------------------------- */
  pthread_mutex_lock( ctr_a->mutex_p );
    ctr_a->prt = my_counter_printer;
  pthread_mutex_unlock( ctr_a->mutex_p );

  sleep(2); /* sleep again */

  /* again doing incrementations and printing values of counters */
  /* ----------------------------------------------------------- */
  for( idx = 0; idx < 5; idx++ )
  {
    ctr_b->incr(ctr_a);
    ctr_b->incr(ctr_b);
    ctr_b->prt(ctr_b);
    ctr_b->prt(ctr_a);
    sleep(1);
  }


  /* wait for all created threads to be finished */
  /* ------------------------------------------- */
  for( idx = 0; idx < NUM_THREADS; idx++ )
  {
    pthread_join( thread_id_array[idx], NULL );
  }


  /* OK, now, when no one uses the counters anymore, we can free them */
  /* ---------------------------------------------------------------- */
  free_counter( ctr_a ); ctr_a = NULL;
  free_counter( ctr_b ); ctr_a = NULL;


  return 0;
}
   

I hope you had some fun (or possibly insights), following me developing some C-Code. I was influenced by usage of a different programming language (OCaml) and this has invoked to do it differently even in C.
DISCLAIMER: The above code is a principially implementation. Return values of the thread functions must be added. I do it later, if time allows me. If you try this code, please have it in mind to add return-value checks (error checking) to the code.
One also could change the return values of the counter-functions to give back an integer value with a status.
But those implementation details were not what this text is about.

Oliver Bandel,
Sa 7. Jun 01:01:18 CEST 2008,
Sa 7. Jun 01:34:31 CEST 2008,
Sa 7. Jun 18:13:57 CEST 2008,
Sa 7. Jun 19:11:53 CEST 2008,
So 8. Jun 19:33:21 CEST 2008,
Mon Jun 9 18:53:50 CEST 2008,
Mon Jun 9 19:08:41 CEST 2008,
Mon Jun 9 19:33:31 CEST 2008,
Thu Jun 19 10:25:36 CEST 2008,