linux 多线程recv安全吗,在多线程环境中recv()不会被信号中断

我有一个处于阻塞recv()循环中的线程,我想终止(假设不能将其更改为select()其他任何异步方法)。

我也有一个捕获的信号处理程序,SIGINT理论上它应该recv()返回错误并errno设置为EINTR。

但是事实并非如此,我认为这与应用程序是多线程的事实有关。还有另一个线程,正在等待pthread_join()呼叫。

这里发生了什么事?

编辑:

好的,现在我将信号从主线程显式传递给所有阻塞recv()线程pthread_kill()(这导致SIGINT安装了相同的全局信号处理程序,尽管多次调用是良性的)。但是recv()通话仍然没有畅通。

编辑:

我编写了一个代码示例来重现该问题。

主线程将套接字连接到行为异常的远程主机,该主机不会让连接断开。

所有信号均被阻止。

读取线程线程已启动。

Main解除封锁并安装的处理程序SIGINT。

读取线程解除阻塞并安装的处理程序SIGUSR1。

主线程的信号处理程序将a发送SIGUSR1到读取线程。

有趣的是,如果我替换recv()为sleep()它,就可以了。

聚苯乙烯

或者,您可以仅打开UDP套接字而不使用服务器。

客户

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

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;

}

服务器

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值