/***************************************************************************
 *   Copyright (C) 2005 by Brian Lauber   *
 *   bml8@case.edu   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#define _REENTRANT

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

struct LaDeDaArgs
{
  pthread_t        id; // The id of the current thread
  pthread_mutex_t *mutex;
};

void* LaDeDa(void *args)
{
  struct LaDeDaArgs *myArgs = args; // Recast the arguments to their real type
  int i = 0;
  printf("Created thread %u\n", myArgs->id);

  for(i = 0; i < 5; ++i)
  {
    pthread_mutex_lock(myArgs->mutex);
    printf("Thread %u locks mutex\n", myArgs->id);
    sleep(1);
    printf("Thread %u unlocks mutex\n", myArgs->id);
    pthread_mutex_unlock(myArgs->mutex);
  }
}

int main(int argc, char **argv)
{
  unsigned int         i = 0;
  unsigned int         thread_count = 0;
  struct   LaDeDaArgs *thread_args;
  pthread_mutex_t      mutex;

  pthread_mutex_init(&mutex, NULL); // Initialize mutex to default attributes (unlocked)

  // Ask the user how many threads (s)he wants to create
  printf("How many threads do you want to create? ");
  scanf("%u", &thread_count);

  // Create LaDeDaArgs structures for each of these threads
  thread_args = malloc(thread_count * sizeof(struct LaDeDaArgs));

  // Create the threads, giving each of them their own unique argument structure
  for(i = 0; i < thread_count; ++i)
  {
    thread_args[i].mutex = &mutex; // Give this thread access to the mutex

    // This next line creates the thread.  The first argument ensures that the new thread
    // will have access to its own thread id.  The last argument is passing the unique
    // thread_arg to the thread
    pthread_create( &(thread_args[i].id), NULL, LaDeDa, &(thread_args[i]));
  }

  // Wait for all the threads to exit
  for(i = 0; i < thread_count; ++i)
    pthread_join(thread_args[i].id, NULL);
  free(thread_args); // Free the memory that contained the thread arguments
  pthread_mutex_destroy(&mutex); // Clean up resources associated w/ mutex
                                 // (in this case, the mutex required no special resources,
                                 //  so this call is actually unnecessary)

  printf("Exiting program\n");
  return EXIT_SUCCESS;
}

