c /中断系统调用/ fork与线程

时间:2011-05-17 11:48:08

标签: c sockets pthreads fork

我发现线程实现存在问题,这对我来说很奇怪。也许有些人可以向我解释,会很棒。

我正在开发类似代理的程序,一个程序(在不同的机器上运行),它通过eth0接收数据包并通过ath0(无线)发送到另一台完全相同的机器。实际上我完全不确定是什么导致了我的问题,那是因为我对所有事情都是新手,linux和c编程。

我开始两个线程,

  • 一个正在eth0上侦听(套接字)传入数据包并通过ath0(也是套接字)发送出去
  • ,另一个线程正在侦听ath0并通过eth0发送。

如果我使用线程,我会收到类似的错误:

sh-2.05b# ./socketex 
Failed to send network header packet.
: Interrupted system call

如果我使用fork(),程序按预期工作。 有人可以向我解释这种行为吗?

只是为了显示发件人实现,这里有代码片段:

while(keep_going) {
    memset(&buffer[0], '\0', sizeof(buffer));

    recvlen = recvfrom(sockfd_in, buffer, BUFLEN, 0, (struct sockaddr *) &incoming, &ilen);
    if(recvlen < 0) {
        perror("something went wrong / incoming\n");
        exit(-1);
    }

    strcpy(msg, buffer);
    buflen = strlen(msg);

    sentlen = ath_sendto(sfd, &btpinfo, &addrnwh, &nwh,  buflen, msg, &selpv2, &depv);

    if(sentlen == E_ERR) {
        perror("Failed to send network header packet.\n");
        exit(-1);
    }
}

UPDATE :我的主文件,启动线程或进程(fork)

int main(void) {

port_config pConfig;

memset(&pConfig, 0, sizeof(pConfig));
pConfig.inPort = 2002;
pConfig.outPort = 2003;

pid_t retval = fork();

if(retval == 0) {
    // child process
    pc2wsuThread((void *) &pConfig);
} else if (retval < 0) {
    perror("fork not successful\n");
} else {
    // parent process
    wsu2pcThread((void *) &pConfig);
}

/*
wint8 rc1, rc2 = 0;

pthread_t pc2wsu;
pthread_t wsu2pc;

rc1 = pthread_create(&pc2wsu, NULL, pc2wsuThread, (void *) &pConfig);
rc2 = pthread_create(&wsu2pc, NULL, wsu2pcThread, (void *) &pConfig);

if(rc1) {
    printf("error: pthread_create() is %d\n", rc1);
    return(-1);
}

if(rc2) {
    printf("error: pthread_create() is %d\n", rc2);
    return(-1);
}

pthread_join(pc2wsu, NULL);
pthread_join(wsu2pc, NULL);
*/
return 0;
}

有帮助吗?

更新 05/30/2011

-sh-2.05b# ./wsuproxy 192.168.1.100
mgmtsrvc
mgmtsrvc
Failed to send network header packet.
: Interrupted system call
13.254158,75.165482,DATAAAAAAmgmtsrvc
mgmtsrvc
mgmtsrvc

仍然可以看到中断的系统调用,如上所示。 我阻止了所有信号:

sigset_t signal_mask;
sigfillset(&signal_mask);
sigprocmask(SIG_BLOCK, &signal_mask, NULL);

两个线程在相同的接口上工作,但在不同的端口上。问题似乎仍然出现在同一个地方(请在第一个代码段中找到它)。我不能再进一步了解如何解决这个问题。也许你们中的一些人可以再次帮助我。

提前致谢。

2 个答案:

答案 0 :(得分:6)

EINTR本身并不表示错误。这意味着您的进程在sendto系统调用时收到了一个信号,并且系统调用尚未发送任何数据(这很重要)。

在这种情况下你可以重试发送,但好的方法是找出导致中断的信号。如果这是可重现的,请尝试使用strace

如果您是发送信号的人,那么,您知道该怎么做: - )

请注意,在linux上,即使您没有自己安装处理程序,也可以在EINTR(以及其他一些函数)上收到sendto。如果出现这种情况:

  • 进程停止(例如通过SIGSTOP)并重新启动(使用SIGCONT)
  • 您已在套接字上设置发送超时(通过SO_SNDTIMEO)

    有关详细信息,请参阅signal(7)手册页(位于最底部)。

    因此,如果您“暂停”您的服务(或其他内容),则需要EINTR,您应该重新开始通话。

  • 答案 1 :(得分:3)

    请记住,如果您正在使用带有信号的线程,那么当传送给进程时,给定信号可以传送到信号掩码未阻塞信号的任何线程。这意味着如果您在一个线程中阻止了传入信号,而在另一个线程中没有阻塞传入信号,则非阻塞线程将接收信号,如果信号没有信号处理程序设置,您将最终使用该信号的默认行为整个过程的信号(即所有线程,信号阻塞线程和非信号阻塞线程)。例如,如果信号的默认行为是终止进程,则捕获该信号并执行其默认行为的一个线程将终止所有线程的整个进程,即使某些线程可能已经屏蔽了该信号。此外,如果您有两个未阻塞信号的线程,则确定哪个线程将处理该信号。因此,混合信号和线程通常不是一个好主意,但规则有例外。

    您可以尝试的一件事是,因为生成线程的信号掩码是从生成线程继承的,所以要创建一个守护程序线程来处理信号,在程序开始时,您阻止所有传入的信号(或者至少所有非重要信号),然后产生你的线程。现在那些生成的线程将忽略父线程的阻塞信号掩码中的任何传入信号。如果您需要处理某些特定信号,您仍然可以将这些信号作为主进程的阻塞信号掩码的一部分,然后生成线程。但是当你生成线程时,将一个线程(甚至可能是生成所有工作线程后的主进程线程)作为“守护进程”线程,等待使用{{1}的那些特定传入(现在被阻塞)信号}。然后,当该进程接收到给定信号时,该线程将调度所需的任何功能。这样可以避免信号在其他工作线程中中断系统调用,但仍允许您处理信号。

    您的分叉版本可能没有问题的原因是因为如果信号到达一个父进程,它不会传播到任何子进程。所以,如果可以的话,我会尝试查看终止系统调用的信号,并在线程版本中阻止该信号,如果需要处理它,请创建一个守护程序线程来处理该信号到达,其余的线程阻止了这个信号。

    最后,如果您无法访问任何外部库或调试器等,以查看到达的信号,您可以设置一个简单的过程来查看可能到达的信号。您可以尝试以下代码:

    sigwait()