2016-07-26 3 views
-2

Je veux casser sleep (3) dans un autre fil de mon fil principal. Pour ce faire, j'ai pensé utiliser raise (sig) et continuer le code après avoir rompu cet appel système.Comment réveiller le sommeil (3) ing thread

Alors, quel signal dois-je utiliser pour provoquer sleep et retourner EINTR?

Le code que j'ai écrit jusqu'à présent:

void *event_loop (void *threadid) 
{ 
    int rc; 
    long tid; 
     do{ 
     rc = sleep(20); 
     printf ("return from sleep with %d", rc); 
     fprintf(stderr, "Value of errno: %d\n", errno); 
     } while (errno == EINTR); 
     tid = (long)threadid; 
     printf("Hello World! It's me, thread #%ld! = %d\n", tid); 

} 

void main(int argc, char *argv[]) 
{ 
    pthread_t threads[NUM_THREADS]; 
    int rc; 
    long t; 
    int sig=SIGABRT ; // which signal??? 
    int i=0; 
    printf("Main THREAD\n"); 
    for(t=0;t<2;t++){ 
    printf("In main: creating thread %ld\n", t); 
    rc = pthread_create(&threads[t], NULL, event_loop, (void *)t); 
    if (rc){ 
     printf("ERROR; return code from pthread_create() is %d\n", rc); 
     exit(-1); 
     } 
    } 
    sleep(2); 
    printf("rasing signal now from main thread...\n"); 
    raise(sig); 
    pthread_exit(NULL); 
} 
+3

[problème XY] classique (http://xyproblem.info). Qu'est-ce que vous essayez vraiment de faire? –

+0

Le programme que j'ai joint devrait être expliqué, j'essaie de générer EINTR par raise() – bzzzz7

+1

J'ai reformulé votre question, de sorte qu'elle exprime le problème que vous voulez résoudre. – a3f

Répondre

-1

Lorsque vous appuyez sur Ctrl + C, le système d'exploitation envoie un signal aux process.This envoie SIGINT signal SIGINT (« interruption de programme ») est l'un des signaux de terminaison.SIGINT est un signal spécial car il peut être manipulé (attrapé) par votre programme. L'action par défaut de SIGINT est la fin du programme. Pour changer l'action par défaut d'un signal, vous devez enregistrer le signal à attraper. Pour enregistrer un signal dans un programme C (au moins dans les systèmes POSIX) il y a deux fonctions

  1. signal(int signum, sighandler_t handler);
  2. sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

Ces fonctions nécessitent l'signal.h d'en-tête à inclure dans votre C code.

exemple:

#include ... 
#include ... 
#include<signal.h> 
void handler(int sig){ 
cout << "Interrupt signal (" << signum << ") received.\n"; 
} 
int main() 
{ 
    //registering signal by signal function 
    signal(SIGINIT,handler); 

    //your code 

while(++i){ 
     cout << "Going to sleep...." << endl; 
     if(i == 3){ 
      raise(SIGINT); 
     } 
     sleep(1); 
    } 
//your code 

    return 0; 
} 
+0

Je ne veux pas utiliser le gestionnaire. Je veux provoquer une interruption qui casse l'appel système dans le thread diffrren et le vérifie comme ça: if (errno == EINTR) {..restart l'appel système ... } – bzzzz7

+0

vous pouvez utiliser le signal SIGABRT alors –

+0

n'a pas fonctionné, je me suis « Aborted (core dumped) » Je joins mon programme, je l'espère maintenant ma question sera plus claire. – bzzzz7

1

Vous pouvez avoir l'autre thread blocked on a condition variable with a timeout:

#include <pthread.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <sys/time.h> 
#include <errno.h> 

pthread_cond_t  cond = PTHREAD_COND_INITIALIZER; 
pthread_mutex_t  mutex = PTHREAD_MUTEX_INITIALIZER; 
int interrupted; 

#define WAIT_TIME_SECONDS 20 
void *event_loop (void *arg) 
{ 
    struct timespec ts; 
    struct timeval tv; 

again: 
    gettimeofday(&tv, NULL); 

    ts.tv_sec = tv.tv_sec; 
    ts.tv_nsec = tv.tv_usec * 1000; 
    ts.tv_sec += WAIT_TIME_SECONDS; 

    pthread_mutex_lock(&mutex); 
    while (!interrupted) { 
     int rc = pthread_cond_timedwait(&cond, &mutex, &ts); 
     if (rc == ETIMEDOUT) { 
      printf("Timed out!\n"); 
      pthread_mutex_unlock(&mutex); 
      goto again; 
     } 
    } 
    printf("Woke up!\n"); 
    interrupted = 0; 
    pthread_mutex_unlock(&mutex); 
    goto again; 
} 

int main(void) { 
    pthread_t thread; 
    pthread_create(&thread, NULL, event_loop, NULL); 
    while (getchar() != EOF) { 
     pthread_mutex_lock(&mutex); 
     interrupted = 1; 
     pthread_cond_signal(&cond); 
     pthread_mutex_unlock(&mutex); 
    } 
} 

Si vous voulez avoir la signalisation déclenchée par un signal comme SIGINT, utilisez sigwait dans un thread dédié ou utiliser Semaphores. Les variables de condition ne sont pas sécurisées par un signal asynchrone.

2

Ce n'est pas un signal qui interrompt un appel système bloquant; c'est la livraison du signal au gestionnaire enregistré (qui n'a pas été installé avec les drapeaux SA_RESTART) qui provoque l'interruption d'un appel système bloquant.

Voici un exemple. La première fonction est un gestionnaire de signal vide (forme longue, donc approprié pour les deux signaux POSIX, ainsi que les signaux en temps réel SIGRTMIN+0 à SIGRTMAX-1). La deuxième fonction est l'installateur du gestionnaire.

#define _POSIX_C_SOURCE 200809L 
#include <stdlib.h> 
#include <signal.h> 
#include <string.h> 
#include <errno.h> 
#include <stdio.h> 

static void empty_handler(int signum, siginfo_t *info, void *context) 
{ 
} 

/* Install empty handler for the specified signal. 
* Returns 0 if success, errno error code otherwise. 
*/ 
static int install_empty_handler(const int signum) 
{ 
    struct sigaction act; 

    memset(&act, 0, sizeof act); 
    sigemptyset(&act.sa_mask); 
    act.sa_sigaction = empty_handler; 
    act.sa_flags = SA_SIGINFO; 
    if (sigaction(signum, &act, NULL) == -1) 
     return errno; 

    return 0; 
} 

Dans votre main(), disons que vous exécutez

if (install_empty_handler(SIGUSR1)) { 
     fprintf(stderr, "Cannot install signal handler: %s.\n", strerror(errno)); 
     return EXIT_FAILURE; 
    } 

avant de créer des threads. (Les gestionnaires de signal sont toujours assignés à tous les threads d'un processus, vous ne pouvez pas définir un gestionnaire pour un thread et un autre pour un autre thread.Vous pouvez vérifier l'ID de thread actuel dans le gestionnaire installé, et faire des choses basées dessus. il n'est pas nécessaire de les installer avant de créer les threads, il est plus facile de les installer avant de créer les threads, et il reste beaucoup moins de fenêtres de course.)

pthread_t somethread; avec somethread un thread qui est dans un appel système bloquant.

Si vous appelez, de tout fil,

pthread_kill(somethread, SIGUSR1); 

le signal SIGUSR1 est envoyé à ce fil.

(Notez que le pthread_kill() appel retourne immédiatement, et vous ne devez pas présumer que le signal a été livré encore à ce moment-là. Vous avez besoin d'un autre mécanisme si vous voulez une notification de livraison trop. En outre, le signal est délivré premier, le syscall de blocage est interrompue seulement après la livraison, et si le système est sous une charge lourde, il peut y avoir un délai mesurable entre les deux Habituellement pas, je ne l'ai vu millisecondes, mais ne préjugent pas à ce sujet. . Si vous avez besoin d'une notification, ont le syscall interrompu le faire après le remarque a été interrompue.)

la livraison du signal à l'installation 0 La fonctionprovoque l'interruption du syscall de blocage dans le même thread. L'appel échouera, renvoyant soit un nombre court (pour certains types de sockets), soit -1 avec errno == EINTR.

Si vous utilisiez à la place raise(SIGUSR1), le noyau peut choisir n'importe quel thread entre les threads du processus pour gérer le signal. (À l'exception des fils qui ont dit le noyau qu'ils souhaitent « bloquer » le signal via pthread_sigmask() ou sigprocmask(), ou si elles ont hérité d'un tel bloc du fil qui a créé ce fil.) Quoi qu'il en soit, si ce fil est dans un syscall blocage , il sera interrompu (en raison de la livraison du signal); s'il fait quelque chose d'autre, le fil est juste "emprunté" pendant un moment, et il n'y a vraiment aucun signe de l'interruption.


Il sont cas où ce mécanisme est utile. En particulier, je l'ai utilisé avec des minuteries délai d'attente (en utilisant timer_create(CLOCK_MONOTONIC, &event, &timer) et timer_settime() pour définir l'événement déclencheur initial du délai d'attente, puis par des répétitions à intervalles courts rapides, toutes les quelques millisecondes) lors de l'utilisation des bibliothèques externes avec prise en charge du délai d'attente faible/glitch prises accès. Même une médiocre bibliothèque n'essaiera pas un blocage plus de quelques fois dans le pire des cas, si tous échouent avec une erreur EINTR - bien sûr, le cas courant, typique, est que le premier force la bibliothèque à rapporter le erreur immédiatement. Ce sont les cas de coin qui me dérangent vraiment; Je veux seulement publier du code robuste qui n'est pas enclin à basculer juste parce que la lune se trouve dans la mauvaise phase.