recv() n'est pas interrompu par un signal en environnement multithread

J'ai un fil qui se trouve dans un blocage recv() boucle et je veux mettre fin (à supposer que cela ne peut pas être changé à select() ou de toute autre approche asynchrone).

J'ai aussi un gestionnaire de signal que les prises SIGINT et, théoriquement, il devrait faire recv() de retour avec l'erreur et errno ensemble de EINTR.

Mais il ne l'est pas, ce qui je suppose a quelque chose à voir avec le fait que l'application est multi-thread. Il y a aussi un autre thread, qui est entre-temps d'attente sur un pthread_join() appel.

Ce qui se passe ici?

EDIT:

OK, maintenant j'ai choisi de fournir le signal à l'ensemble de blocage recv() threads via pthread_kill() depuis le thread principal (qui se traduit dans le même SIGINT gestionnaire de signal installé, même si de multiples appels sont bénignes). Mais recv() appel n'est toujours pas débloqué.

EDIT:

J'ai écrit un exemple de code qui reproduit le problème.

  1. Thread principal se connecte à un socket à un comportement anormal de l'hôte distant qui ne permet pas de connexion aller.
  2. L'ensemble des signaux bloqués.
  3. Lire le thread thread est démarré.
  4. Principal débloque et installe gestionnaire pour SIGINT.
  5. Lire fil débloque et installe gestionnaire pour SIGUSR1.
  6. Thread principal du gestionnaire de signal envoie un SIGUSR1 à la lecture du thread.

Fait intéressant, si je remplace le recv() avec sleep() il est interrompu à l'amende juste.

PS

Alternativement, vous pouvez simplement ouvrir un socket UDP au lieu d'utiliser un serveur.

client

#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
static void
err(const char *msg)
{
perror(msg);
abort();
}
static void
blockall()
{
sigset_t ss;
sigfillset(&ss);
if (pthread_sigmask(SIG_BLOCK, &ss, NULL))
err("pthread_sigmask");
}
static void
unblock(int signum)
{
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, signum);
if (pthread_sigmask(SIG_UNBLOCK, &ss, NULL))
err("pthread_sigmask");
}
void
sigusr1(int signum)
{
(void)signum;
printf("%lu: SIGUSR1\n", pthread_self());
}
void*
read_thread(void *arg)
{
int sock, r;
char buf[100];
unblock(SIGUSR1);
signal(SIGUSR1, &sigusr1);
sock = *(int*)arg;
printf("Thread (self=%lu, sock=%d)\n", pthread_self(), sock);
r = 1;
while (r > 0)
{
r = recv(sock, buf, sizeof buf, 0);
printf("recv=%d\n", r);
}
if (r < 0)
perror("recv");
return NULL;
}
int sock;
pthread_t t;
void
sigint(int signum)
{
int r;
(void)signum;
printf("%lu: SIGINT\n", pthread_self());
printf("Killing %lu\n", t);
r = pthread_kill(t, SIGUSR1);
if (r)
{
printf("%s\n", strerror(r));
abort();
}
}
int
main()
{
pthread_attr_t attr;
struct sockaddr_in addr;
printf("main thread: %lu\n", pthread_self());
memset(&addr, 0, sizeof addr);
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (socket < 0)
err("socket");
addr.sin_family = AF_INET;
addr.sin_port = htons(8888);
if (inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) <= 0)
err("inet_pton");
if (connect(sock, (struct sockaddr *)&addr, sizeof addr))
err("connect");
blockall();
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
if (pthread_create(&t, &attr, &read_thread, &sock))
err("pthread_create");
pthread_attr_destroy(&attr);
unblock(SIGINT);
signal(SIGINT, &sigint);
if (sleep(1000))
perror("sleep");
if (pthread_join(t, NULL))
err("pthread_join");
if (close(sock))
err("close");
return 0;
}

serveur

import socket
import time
s = socket.socket(socket.AF_INET)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('127.0.0.1',8888))
s.listen(1)
c = []
while True:
(conn, addr) =  s.accept()
c.append(conn)
J'éprouve quelque chose de similaire (bien que différentes dans certains de ses aspects), avec un seul thread de l'application (un seul processus sans autre thread). Je crois donc que le multi‑threading n'est pas la cause du comportement ici.

OriginalL'auteur Alex B | 2010-08-27