2017-01-09 3 views
0

рассмотрим следующую ситуацию: один поток (позволяет называть его A) инициализирует, устанавливает состояние сокета с listen(), а затем ждет с accept(). Соединение поступает в гнездо A, accept() возвращает действительный fd. Создается новый поток (B) (с использованием std::thread), а полученный fd передается вызываемому объекту, который запускается в потоке B. Чтение (с использованием read()) для fd завершается с ошибкой, а errno - 9 EBADFD. Thread A вызывает join() на B. Когда B не создается и fd используется (все еще через тот же вызываемый объект), чтение завершается без сбоев. Зачем? Ниже приведен код, иллюстрирующий эту ситуацию.Linux Socket файловый дескриптор с потоками

BaseFun::BaseFun(char* bufferAdr, int socket): 
    socket_fd(socket) 
    buffer(bufferAdr) 
{} 

BaseFun::~BaseFun() 
{ 
    close(socket_fd); 
} 

char* BaseFun::buffer_read() 
{ 
    if(read(socket_fd, buffer, BUFF_SIZE-1) < 0) { 
     std::cout<<"ERROR while READ\n"<<"ERRNO: "<<errno<<"\n"<<"FD: "<<socket_fd<<"\n"; 
    } 
    return buffer; 
} 

DisplayMsgFun::DisplayMsgFun(char* buffer, int socket) : 
    BaseFun(buffer, socket) 
{} 

void DisplayMsgFunFun::operator()() 
{ 
    std::cout<<"Message:\n\t"<<buffer_read()<<"\nEND\n"; 
} 

Отрывок, где выше, называется:

void Server::server_run() 
{ 
    sockaddr_in client_addr; 
    socklen_t c_len = sizeof(client_addr); 

    client_fd = accept(sock_fd, (sockaddr*)&client_addr, &c_len); 
    DisplayMsgFun dm(server_buffers->front().data(), client_fd); 
    std::thread job(dm); 
    job.join(); 
} 

И main()

int main() 
{ 
    Server srv(PORT); 
    if (srv.server_create()) { 
     std::cout << "Server bind!\n"; 
     srv.server_run(); 
    } 
    else { 
     std::cout << "Bind fail! ERRNO: "<<errno<<"\n"; 
     return -1; 
    } 
    return 0; 
} 
+0

Несвязанный с вашей проблемой, но зачем создавать поток, если следующая вещь, которую вы делаете, это просто подождать? Я предполагаю, что вы делаете что-то еще между созданием потока и вызовом 'join'? Может быть, проблема в том, что * часть (что вы нам не показываете)? –

+0

Мне было бы интересно узнать, как вы это исправите. Я знаю достаточно C++, чтобы определить проблему (за мой ответ), но не исправлять ее. Интересно, достаточно ли написать 'std :: thread job (std :: ref (dm))'. – Alnitak

+0

@Alnitak Я проверил быстрый тест и 'std :: ref()' решает проблему. Но я думаю, этого будет недостаточно в «крупном масштабе», или когда я попытаюсь избавиться от этого вызова 'join()'. – Ufo

ответ

2

Вы, кажется, передавая копию от DisplayMsgFun объекта к std::thread конструктора, это означает, что оригинальная копия уничтожается, автоматически вызывая ::close за ваш дес tructor.

Смежные вопросы