c++linuxrecvsetsockopt

Why recv returns -1 and errno=EINTR when set SO_RCVTIMEO?


This problem only hapens when socket is set timeout with SO_RCVTIMEO.

recv should block for 3sec. But it returns because of EINTR as soon as another thread starts.

If I run thread t2, recv in thread t1 will return -1 without blocking and sets errno to EINTR.

But recv in thread t1 functions normally when thread t2 is not started, it just blocks for 3 seconds.

If thread t2 runs before thread t1, recv also works properly.

I found it fails every time when I was debuging with SlickEdit or gdb. But works properly when it runs in terminal.

Here is code:

test.cpp: link -pthread to use <thread> or thread throws exception

#include<unistd.h>
#include<netdb.h>
#include<string.h>
#include<thread>

int socket_fd;
sockaddr_in server_addr;

void recvThread()
{
    char pData[4096];
    int len = recv(socket_fd,pData,4096,0);
    if(len<=0)
    {
        printf("len:%d\n",len);
        printf("errno:%d\n",errno);
    }
}

void otherThread()
{
    while(1)
    {
         sleep(1);
    }
}

int main()
{
    hostent *host;
    if((host=gethostbyname("127.0.0.1"))==NULL)
    {
         return 1;
    }
    memset(&server_addr, 0, sizeof(sockaddr_in));
    server_addr.sin_family=AF_INET;
    server_addr.sin_port=htons(8887);
    server_addr.sin_addr=*((in_addr*)host->h_addr);
    bzero(&(server_addr.sin_zero),8);

    socket_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    timeval timeout = {3,0};
    setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeval));
    if(connect(socket_fd, (sockaddr*)&server_addr, sizeof(server_addr))<0)
    {
         return 1;
    }

    std::thread t1(recvThread);
    std::thread t2(otherThread);
    t1.join();
    t2.join();
}

Solution

  • See comment on EINTR from "Some programmer dude"

    The debugger (gdb), unless can set/modify breakpoints asynchronously, needs to stop the target (your task), set the breakpoints, then resume it. To stop it it could send SIGINT, which would thus cause EINTR on your system blocked calls.

    If you using GNU C library you could use TEMP_FAILURE_RETRY macro, see this post: TEMP_FAILURE_RETRY and __USE_GNU