#include <iostream>   // cout, cerr, endl
#include <unistd.h>   // usleep, fork, exec
#include <cstdlib>    // exit
#include <cstdio>     // sscanf, perror
#include <sys/wait.h> // kill, waitpid, SIGKILL
#include <errno.h>    // errno
#include <string.h>   // strerror

// How often to check the child's status (ms)
const int STEP = 5;

// ms is in milliseconds
void sleep_ms(int ms)
{
  usleep(ms * 1000); // 0.001ms sleep
}

// debug
void print_args(int argc, char **argv)
{
  for (int i = 3; i < argc; i++)
    std::cerr << argv[i] << " ";
}

//argv[1] - hard-timeout
//argv[2] - soft-timeout
//argv[3] - executable
//argv[4] - args... to executable
int main(int argc, char ** argv)
{
  if (argc < 3)
  {
    std::cout << "Usage: " << argv[0] << " hard_timeout soft_timeout ";
    std::cout << "exe_to_run args_for_exe ....\n";
    std::cout << "where " << std::endl;
    std::cout << "  hard_timeout - How long to wait until terminating child.\n";
    std::cout << "  soft_timeout - How long to wait until child is now inefficient.\n";
    return 1;
  }

  int hard_timeout; // kill the program at this point
  int soft_timeout; // allow the program to run after this point

  std::sscanf(argv[1], "%d", &hard_timeout);
  std::sscanf(argv[2], "%d", &soft_timeout);

    // Program to exec
  char *exe = argv[3];

  int status;       // child's return code
  int duration = 0; // how long the child has been running for

  pid_t pid = fork();

    // child
  if (pid == 0)
  {
    int execReturn = execvp(exe, argv + 3);
    std::cerr << "Failure! execv error code = " << execReturn << std::endl;
    perror("execvp");
    exit(1);
  }

    // parent
  int result = 0; // return code for OS

  if (pid < 0) // fork failed
  {
    std::cerr << "Failed to fork" << std::endl;
    return 1;
  }
  else
  {
      // long long will allow this code to work with 32-bit and 64-bit systems
    long long waitval = waitpid(pid, &status, WNOHANG);

      // Continue to wait until child finishes, or the wait time expires
    while ((duration <= hard_timeout) && !WIFEXITED(status))
    {
        // The wait failed for some reason
      if (waitval == -1)
      {
        std::cerr << "!!!!! Something bad happened running ";
        print_args(argc, argv);
        std::cerr << " (" << strerror(errno) << ") !!!!!\n";
        return 2;
      }
      sleep_ms(STEP);  // don't busy wait
      duration += STEP;
      waitval = waitpid(pid, &status, WNOHANG);
    }

      // Child exited normally
    if (WIFEXITED(status))
    {
        // Inefficient
      if (duration > soft_timeout)
      {
        std::cout << "\n********** Test took " << duration << " ms. (Inefficient) **********\n";
        result = 3;
      }
      else // Efficient
      {
        //std::cout << "\nTest completed within efficient time limit. (" << soft_timeout << " ms";
        //std::cout << ", actual " << duration << " ms)\n";
      }
    }
    else // Child didn't finish, kill it
    {
      int err;    // kill success/fail
      result = 4; // code indicating child took too long

      err = kill(pid, SIGKILL);
      if (err)
      {
        std::cerr << "kill failed!" << std::endl;
        perror("kill");
        result = 5; // kill failed
      }
      std::cout << "\n********** Test took too long to complete (over " << hard_timeout <<  "ms). **********\n";
    }
    // At this point, the child has finished or has been terminated (hopefully)
  }

  return result;
}
Simple tester app:
#include <unistd.h> // usleep
#include <stdlib.h> // atoi

void sleep_ms(int ms) 
{ 
  usleep(ms * 1000); 
}

int main(int argc, char **argv)
{
  int ms = 1000;

  if (argc > 1)
    ms = atoi(argv[1]);

  sleep_ms(ms);

  return 0;
}