void *counter_routine( MPI_Comm *counter_comm_p )
{
    int incr, ival = 0;
    MPI_Status status;
    while (1) {
	MPI_Recv( &incr, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG,
		  *counter_comm_p, &status );
	if (status.MPI_TAG == 1) return;
	MPI_Send( &ival, 1, MPI_INT, status.MPI_SOURCE, 0, 
		  *counter_comm_p );
	ival += incr;
    }
}
/* We discuss how to eliminate this global var in the text */
static pthread_t thread_id;
void init_counter( MPI_Comm comm, MPI_Comm *counter_comm_p )
{
    int rank;
    MPI_Comm_dup( comm, counter_comm_p );
    MPI_Comm_rank( comm, &rank );
    if (rank == 0) 
	pthread_create( &thread_id, NULL, counter_routine, 
			counter_comm_p );
}
/* Any process can all this to fetch and increment by value */
void counter_nxtval( MPI_Comm counter_comm, int incr, int *value )
{
    MPI_Send(&incr, 0, MPI_INT, 0, 1, counter_comm);
    MPI_Recv(value, 1, MPI_INT, 0, 0, counter_comm, MPI_STATUS_IGNORE);
}
/* Every process in counter_comm (including rank 0!) 
   must call stop counter */
void stop_counter( MPI_Comm *counter_comm_p )
{
    int rank;
    MPI_Barrier( *counter_comm_p );
    MPI_Comm_rank( *counter_comm_p, &rank );
    if (rank == 0) {
	MPI_Send( MPI_BOTTOM, 0, MPI_INT, 0, 1, *counter_comm_p );
	pthread_join( thread_id, NULL );
    }
    MPI_Comm_free( counter_comm_p );
}
