// hilos-v2.cpp - Un programa C++ visto como un proceso con
//                múltiples hilos
#include <iostream>
#include <string>
#include <pthread.h>
using namespace std;

// Tipo que define los parámetros de un hilo
typedef struct
{
  int id;
  int cuenta;
  string str;
} pthread_param_t;

int random(int n)
{
  static bool primera_vez = true;
  if (primera_vez)
  {
    srand(time(0));
    primera_vez = false;
  }
  return (rand() % n)+1; // valor entre 1 y n
}

// Función que ejecutan los hilos secundarios
void *tomarMuestra(pthread_param_t *p)
{
  p->cuenta = random(15);
  for (int i = 0; i < p->cuenta; i++)
    cout << p->str << endl;
  return &p->id;
}

void resultados(pthread_param_t param[], int n)
{
  int i, total = 0;
  for (i = 0; i < n; i++)
  {
    cout << param[i].str << ": " << param[i].cuenta << endl;
    total += param[i].cuenta;
  }
  cout << "Total: " << total << endl;
}

void error(int codigo, char *str)
{
  cerr << codigo << ": " << str << endl;
  exit(1);
}

typedef void *(*ptrfnthr)(void *);

// Hilo primario (hilo principal)
int main()
{
  const int NHILOS = 3;
  int i, cod, *estado;
  // Identificadores de los hilos
  pthread_t hilo[NHILOS];
  // Parámetros de los hilos
  pthread_param_t param[NHILOS];
  
  for (i = 0; i < NHILOS; i++)
  {
    // Iniciar la estructura i con los argumentos para el hilo i
    param[i].id = i;
    param[i].cuenta = 0;
    param[i].str = "Tomando muestra de tipo ";
    param[i].str.append(1, char('A'+i));
  }

  // Crear los n hilos e iniciar su ejecución
  for (i = 0; i < NHILOS; i++)
  {
    cod = pthread_create(&hilo[i], 0,
                         (ptrfnthr)tomarMuestra,
                         (void *)&param[i]);
    if (cod) error(cod, "pthread_create");
  }
  
  // Esperar a que los hilos secundarios terminen
  for (i = 0; i < NHILOS; i++)
  {
    cod = pthread_join(hilo[i], (void **)&estado);
    if (cod) error(cod, "pthread_join");
    // Verificar cómo finaliza el hilo i y liberar sus recursos
    if (*estado != i)
    {
      cerr << "el hilo " << i << " ha terminado anormalmente\n";
      exit(1);
    }
  }
  // Mostrar resultados
  resultados(param, NHILOS);
  
  system("pause");
}

