1

I'm trying to create a program where the user is asked a question and has a few seconds to answer the question, or else the program stops input.

Now my problem is I'm unable to get my program not to block input. I am able to input data, but when I don't and the timer runs out it keeps asking for input.

I'm running on Windows and use Code::Blocks in case it's important. If someone could explain to me what I'm doing wrong, it would be appreciated.

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

int key = 0;
int GradeTotal = 0;

//runs an empty loop every iteration F.E. for loop
void timer(int seconds)
{
    clock_t wait = (clock() + (seconds * CLOCKS_PER_SEC));
    while(clock() < wait){}

}

void timeleft()
{
    int index;

    for(index = 5; index >= 0; index--)
    {
        if(key != 0)
        {
            pthread_exit(timeleft);
        }

        timer(1);

        if(index == 0)
        {
        printf("\n\nTime's up!");
        }
    }
}

void questions()
{
    int key;

    printf("what is 1 + 1?\nAnswer: ");

    while(1)
    {
        if(_kbhit())
        {
            key = _getch();
            printf("%c",key);
            break;
        }
    }
    if(key == 50)
    {
         GradeTotal += 1;
    }  
 }


int main()
{
    pthread_t thread1,thread2;

    int index;
    int seconds = 0;
    pthread_create(&thread1, NULL, questions, NULL);
    pthread_create(&thread2, NULL, timeleft, NULL);
    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("\n\nGrade: %d",GradeTotal);

    return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • 1
    `while(clock() < wait){}` god damn you want destroy my heart ? Use something like `sleep()` – Stargateur Dec 29 '17 at 11:31
  • Some question : https://stackoverflow.com/questions/28382962/wait-for-press-enter-in-c-inside-a-while-loop – Zakaria Charik Dec 29 '17 at 11:33
  • suggest using: `select()` with a timeout value, then when the call to `select()` returns, check if it was due to an error, or due to a timeout, or due to stdin being ready with data, This will still block the thread that it is in, so place it in a separate thread. – user3629249 Dec 30 '17 at 05:07
  • suggest using a call to `setitimer()` and using the appropriate signal handler to catch the expiration of the timer. – user3629249 Dec 30 '17 at 05:11

2 Answers2

1

When time ran out have timeleft() set a global flag, which is tested by questions(), and if set makes the code leave the while (1) loop.

Make sure access to the flag is protected using a mutex.

Talking about "protected access": key is accessed concurrently without protection. Not good.

alk
  • 69,737
  • 10
  • 105
  • 255
1

This exemple use pthread's feature to set up a timer and cancel the thread if something goes wrong, I didn't check any error in this exemple. In real application, you must do it:

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

void *wrapper_handle_question(pthread_cond_t *cond) {
  char buf[2048];
  size_t i = fread(buf, 1, sizeof buf - 1, stdin);
  buf[i] = '\0';
  printf("%s", buf);
  pthread_cond_broadcast(cond);
  return NULL;
}

void *handle_question(void *arg) { return wrapper_handle_question(arg); }

int main(void) {
  pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  pthread_t question;
  pthread_create(&question, NULL, &handle_question, &cond);

  struct timespec ts;
  clock_gettime(CLOCK_REALTIME, &ts);
  ts.tv_sec += 5;

  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  pthread_mutex_lock(&mutex);

  int rc = pthread_cond_timedwait(&cond, &mutex, &ts);
  pthread_mutex_unlock(&mutex);
  if (rc == 0) {
    pthread_join(question, NULL);
  } else {
    pthread_cancel(question);
    printf("timeout!\n");
  }
}
Stargateur
  • 24,473
  • 8
  • 65
  • 91