Question

J'ai écrit mon propre module stop_watch. Cela créera un fil de discussion et s’endormira pendant quelques secondes. Une fois les secondes écoulées, il appelle une fonction de rappel dans le fichier main.c et informe l'utilisateur que le délai a expiré.

C’est pour que l’utilisateur ne dispose que de 3 secondes pour saisir un chiffre et de 5 chiffres. Si le temps expire, le programme doit s'arrêter.

2 problèmes. 1) s'ils entrent le chiffre dans le temps requis. Comment puis-je annuler le fil. Je pensais utiliser thread_kill ou thread_cancel? 2) Comment puis-je terminer la boucle dans la boucle do_while? Comme le scanf se bloque en attendant que l’utilisateur entre.

Merci beaucoup pour vos suggestions,

Mon code ci-dessous:

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

#include "stop_watch.h"

struct data_struct *g_data_struct;

void timeout_cb(int id)
{
    printf("Digit timeout\n");
    free(g_data_struct);
}

int main()
{
    pthread_t thread_id;
    unsigned int digit = 0;

    g_data_struct = (struct data_struct*) calloc(1, sizeof(*g_data_struct));

    if(!g_data_struct)
    {
        printf("=== failed to allocate memory ===\n");
        return 0;
    }

    /* start timer for 3 seconds */
    g_data_struct->seconds = 3;
    g_data_struct->func_ptr = timeout_cb;
    thread_id = start_stopwatch(g_data_struct);

    do
    {
        printf("Enter digit: ");
        scanf("%d", &digit);
    }while(1);

    pthread_join(thread_id, NULL);
    printf("=== End of Program - all threads in ===\n");

    free(g_data_struct);

    return 0;
}



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

#include "stop_watch.h"

pthread_t thread_id;
static id = 10;

/* start sleeping and call the callback when seconds have expired */
static void* g_start_timer(void *args)
{
    void (*function_pointer)(int id);
    int seconds = ((struct data_struct*) args)->seconds;
    function_pointer = ((struct data_struct*) args)->func_ptr;

    sleep(seconds);

    (void) (*function_pointer)(id);

    pthread_exit(NULL);

    return 0;
}

/* Will sleep in its own thread for a period of seconds */
int start_stopwatch(struct data_struct *g_data_struct)
{
    int rc = 0;

    int seconds = g_data_struct->seconds;
    printf("=== start_stopwatch(): %d\n", seconds);

    rc =  pthread_create(&thread_id, NULL, g_start_timer, (void *) g_data_struct);

    if(rc)
    {    
        printf("=== Failed to create thread\n");
        return 1;
    }

    return thread_id;
}

Cette question concerne C99 gcc, au fait.

Était-ce utile?

La solution

Je ne recommanderais pas d'utiliser un fil séparé pour cela en premier lieu. Mais comme cela ressemble à un exercice pour apprendre à utiliser les discussions, je vais y aller.

Vous pouvez définir un indicateur booléen global indiquant si un chiffre a été entré. Dans g_start_timer, juste avant d'appeler function_pointer, vérifiez si l'indicateur a été défini. Si c'était le cas, n'appelez pas la fonction.

Si vous souhaitez que le thread meure plus tôt, avant l’expiration de sa période de veille, vous pouvez utiliser un mutex avec un verrou d’essai.

EDIT: Puisque vous dites que ce n’est pas un exercice, je vais expliquer comment je le ferais. Utilisez une fonction qui peut expirer en attendant l'entrée sur un stdin, telle que select () ou poll (). Ou utilisez alarm () pour interrompre. Voici un exemple d'utilisation de alarm:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

void alarm_signal(int signum)
{
}

int main()
{
    char c;
    unsigned int v = 0;
    struct sigaction act;
    puts("Enter digit: ");

    /* Register dummy handler for alarm */
    act.sa_handler = &alarm_signal;
    act.sa_flags = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGALRM, &act, NULL);

    /* Set timer for 3 seconds */
    alarm(3);

    /* Read the digits */
    errno = 0;
    while(0 != read(STDIN_FILENO, &c, 1))
    {
        if(c < '0' || c > '9')
            break;
        v = v*10 + c - '0';
    }
    if(errno == EINTR)
        puts("Timed out");
    else
        printf("Value is %d\n", v);
    return 0;
}

Autres conseils

Bien sûr, vous pouvez utiliser thread_cancel pour annuler un fil de discussion. En ce qui concerne scanf, vous pouvez penser à utiliser des pipes pour simuler une entrée du terminal.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top